home *** CD-ROM | disk | FTP | other *** search
- /*****
- *
- * Grant's CGI Framework
- * (Common Grant Interface :-)
- * by Grant Neufeld
- * http://arpp.carleton.ca/cgi/framework/
- *
- * CGI.c
- *
- * Standard functions for cgi applications.
- *
- * You must call InitCGIUtil in your application startup.
- * You must install CGIAEHandle as the event handler for the WWWΩsdoc apple event
- * You must write the function:
- * void CustomCGIProcess ( CGIHdl theCGIHdl )
- * which is where you will, guess what, do your application specific processing
- * of the cgi stuff.
- *
- * Do not call any functions begining with lower case 'cgi' - you can use any of the
- * others - but read their comments first for details.
- *
- * watch the homepage for future upgrades
- *
- *
- * Copyright ©1995,1996 by Grant Neufeld
- *
- * gneufeld@ccs.carleton.ca
- * grant@acm.org
- * grant@kagi.com
- *
- * I ask that you let me know of any enhancements (read: bug fixes) to this code.
- * I would also like copies of (or discounts on) anything you produce this with, please.
- *
- * See the License and Limited Warranty Agreement for all the legal stuff including
- * applicable licensing fees.
- *
- *****/
-
- #include "MyConfiguration.h"
- #if kCompileWithCGICode
-
- #define __CGISegment__ 1
-
- #if __profile__ && __MWERKS__
- #include <Profiler.h>
- #endif
- #if kCompileWithExtraQC
- #include <QCAPI.h>
- #endif
- #include <stdio.h>
- #include <string.h>
- #include <Threads.h>
- #if kCompilingForWSAPI
- #include <WSAPI.h>
- #endif
-
- #if kCompilingForWSAPI
- /* normally, "main.c" defines the MainSegment, but for a plug-in we don't use
- "main.c", so we declare "CGI.c" to be the source of the MainSegment */
- #define __MainSegment__ 1
- #endif
-
- #include "globals.h"
-
- #if kCompilingForWSAPI
- #undef __MainSegment__
- #endif
-
- #include "AEFunc.h"
- #include "CustomHandlers.h"
- #include "DebugUtil.h"
- #include "LogUtil.h"
- #include "MemoryUtil.h"
- #include "PrefUtil.h"
- #include "ProcessUtil.h"
- #include "Quit.h"
- #include "StringUtil.h"
-
- /* CGI.h processes differently for CGI.c, this is controlled by defining __CGISegment__ */
- #include "CGI.h"
-
- #undef __CGISegment__
-
-
- /*** CONSTANT DECLARATIONS ***/
-
- #define kHTTPHeaderStrs 10000 // changed from 3000 to support WSAPI
- #define kHTTPHeaderOK 1
- #define kHTTPHeaderRedirect 2
- #define kHTTPHeaderErr 3
- #define kHTTPHeaderPush 4
-
-
- /*** LOCAL VARIABLES ***/
-
- #if kCompileWithThreadedAppleEvents
- static AEEventHandlerUPP vCGIAEResumeCompleteUPP;
- #endif
-
- static char * vNULLString;
-
- #if kCompilingForWSAPI
- SInt16 vMyResFile = nil;
- SInt16 vSavedResFile = nil;
- Boolean vResFileSemaphore = false;
- #endif
-
-
- /*** LOCAL FUNCTION PROTOTYPES ***/
-
- #if kCompilingForWSAPI
-
- static WSAPI_ErrorCode cgiProcessWSAPI ( WSAPI_CommandPBPtr );
- static void cgiWSAPILoadParameters ( CGIHdl );
- #if kCompileWithCGImethod
- static HTTPMethod cgiWSAPIGetParamHTTPMethod ( CGIHdl, WSAPI_ParamKeywords );
- #endif
-
- #if kCompileWithDebugging
- static WSAPI_ErrorCode cgiWSAPIDebugMessage ( WSAPI_CommandPBPtr, char * );
- #else
- #define cgiWSAPIDebugMessage(a,b) (WSAPI_I_NoErr)
- #endif
-
- #else
-
- pascal OSErr cgiAESearchDoc ( AppleEvent *, AppleEvent *, long );
- static OSErr cgiAESearchDocProcess ( CGIHdl );
- static OSErr cgiAEComplete ( CGIHdl, AppleEvent * );
-
- #if kCompileWithThreadedAppleEvents
- pascal void * cgiAESearchDocProcessThread ( void * );
- pascal OSErr cgiAEResumeComplete ( const AppleEvent *, AppleEvent *, long );
- #endif
-
- #if kCompileWithCGImethod
- static OSErr cgiAEGetParamHTTPMethod ( const AppleEvent *, AEKeyword, HTTPMethod *, char *, long );
- #endif
-
- #if kCompileWithCGISendPartial
- p_export OSErr cgiAESendPartial ( CGIHdl, char *, long, Boolean );
- p_export OSErr cgiAESendPartialStart ( CGIHdl, char *, long );
- #endif /* kCompileWithCGISendPartial */
-
- #endif
-
-
- #if kCompileWithCGIActionSupport || kCompilingForWSAPI
- static void cgiSetRole ( CGIHdl );
- #endif
-
- #if kCompileWithCGIFormHandling
- void CGIFormFieldsDispose ( CGIHdl, CGIFormField * );
- #endif /* kCompileWithCGIFormHandling */
-
- static void cgiPostProcess ( CGIHdl );
-
- static void cgiDisposeRecord ( CGIHdl );
-
-
- /*** FUNCTIONS ***/
-
- /* This initialization function MUST be called in the startup sequence of the
- application if you use any of the CGI functions (including the AppleEvent).
- It will not be called when compiling under WSAPI */
- SInt32
- InitCGIUtil ( void )
- {
- #if kCompilingForWSAPI
- SInt32 theErr;
- #else
- OSErr theErr;
- AEEventHandlerUPP theUPP;
- #endif
- #if kCompileWithExtraQC
- QCErr theQCErr;
- #endif
-
- theErr = noErr;
-
- #if !kCompilingForWSAPI
- /* initialize the null string to consist of one character '\0' */
- vNULLString = (char *) MemoryNewPtr ( 1, &theErr );
- if ( vNULLString != NULL )
- {
- vNULLString[0] = nil;
- }
- else
- {
- /* IMPORTANT: we failed initialization
- if we couldn't allocate a one byte string! */
- if ( theErr == noErr )
- {
- /* make sure there's an error value */
- theErr = memFullErr;
- }
-
- return theErr;
- }
- #endif
-
- GetIndString ( gHTTPHeaderOK, kHTTPHeaderStrs, kHTTPHeaderOK );
- if ( gHTTPHeaderOK[nil] != nil )
- {
- P2CStr ( gHTTPHeaderOK );
- gHTTPHeaderOKSize = strlen ( (char *)gHTTPHeaderOK );
- }
- #if kCompilingForWSAPI
- else
- {
- theErr = WSAPI_E_MessageNotHandled; //••• is this good value to use?
- }
- #endif
-
- GetIndString ( gHTTPHeaderRedirect, kHTTPHeaderStrs, kHTTPHeaderRedirect );
- if ( gHTTPHeaderRedirect[nil] != nil )
- {
- P2CStr ( gHTTPHeaderRedirect );
- gHTTPHeaderRedirectSize = strlen ( (char *)gHTTPHeaderRedirect );
- }
-
- GetIndString ( gHTTPHeaderErr, kHTTPHeaderStrs, kHTTPHeaderErr );
- if ( gHTTPHeaderErr[nil] != nil )
- {
- P2CStr ( gHTTPHeaderErr );
- gHTTPHeaderErrSize = strlen ( (char *)gHTTPHeaderErr );
- }
-
- #if !kCompilingForWSAPI
-
- #if kCompileWithCGISendPartial
- GetIndString ( gHTTPHeaderPush, kHTTPHeaderStrs, kHTTPHeaderPush );
- if ( gHTTPHeaderPush[nil] != nil )
- {
- P2CStr ( gHTTPHeaderPush );
- gHTTPHeaderPushSize = strlen ( (char *)gHTTPHeaderPush );
- }
- #endif
-
- /* it's okay to 'lose track' of theUPP since we never want to get rid of it
- until the application quits - at which point it will automatically be
- disposed of, anyway. */
- theUPP = NewAEEventHandlerProc ( cgiAESearchDoc );
- theErr = AEInstallEventHandler ( kAEClassCGI, kAEIDSearchDoc, theUPP, 0L, false );
-
- #if kCompileWithThreadedAppleEvents
- vCGIAEResumeCompleteUPP = NewAEEventHandlerProc ( cgiAEResumeComplete );
- #endif
-
- #endif /* !kCompilingForWSAPI */
-
- #if kCompileWithExtraQC
- theQCErr = QCBlockBoundsCheckNow ();
- theQCErr = QCHeapCheckNow ();
- #endif
-
- return theErr;
- } /* InitCGIUtil */
-
-
- /** MEMORY HANDLING **/
- /* custom wrappers for memory handling under WSAPI.
- these functions get mapped to the normal memory handlers when compiling
- as an AppleEvent CGI application. */
- #pragma mark -
- #if kCompilingForWSAPI
-
- p_export
- Handle
- CGINewHandle ( CGIHdl theCGIHdl, long theSize, OSErr *outErr )
- {
- Handle theHandle;
-
- my_assert ( theCGIHdl != NULL, "\pCGINewHandle: theCGIHdl is NULL" );
-
- theHandle = (Handle) WSAPI_AllocateOSMemory ( (*theCGIHdl)->wsapi, theSize );
-
- if ( outErr != NULL )
- {
- if ( theHandle == NULL )
- {
- *outErr = memFullErr;
- }
- else
- {
- *outErr = noErr;
- }
- }
-
- return theHandle;
- } /* CGINewHandle */
-
- p_export
- Handle
- CGINewHandleClear ( CGIHdl theCGIHdl, long theSize, OSErr *outErr )
- {
- Handle theHandle;
-
- my_assert ( theCGIHdl != NULL, "\pCGINewHandleClear: theCGIHdl is NULL" );
-
- theHandle = (Handle) WSAPI_AllocateOSMemory ( (*theCGIHdl)->wsapi, theSize );
- if ( theHandle == NULL )
- {
- if ( outErr != NULL )
- {
- *outErr = memFullErr;
- }
- }
- else
- {
- if ( outErr != NULL )
- {
- *outErr = noErr;
- }
- /* clear the new handle */
- HLock ( theHandle );
- memset ( *theHandle, nil, theSize );
- HUnlock ( theHandle );
- }
-
- return theHandle;
- } /* CGINewHandleClear */
-
- p_export
- Ptr
- CGINewPtr ( CGIHdl theCGIHdl, long theSize, OSErr *outErr )
- {
- Ptr thePtr;
-
- my_assert ( theCGIHdl != NULL, "\pCGINewPtr: theCGIHdl is NULL" );
-
- thePtr = (Ptr) WSAPI_AllocateMemory ( (*theCGIHdl)->wsapi, theSize );
-
- if ( outErr != NULL )
- {
- if ( thePtr == NULL )
- {
- *outErr = memFullErr;
- }
- else
- {
- *outErr = noErr;
- }
- }
-
- return thePtr;
- } /* CGINewPtr */
-
- p_export
- Ptr
- CGINewPtrClear ( CGIHdl theCGIHdl, long theSize, OSErr *outErr )
- {
- Ptr thePtr;
- #if kCompileWithExtraQC
- QCErr theQCErr;
- #endif
-
- my_assert ( theCGIHdl != NULL, "\pCGINewPtrClear: theCGIHdl is NULL" );
-
- thePtr = (Ptr) WSAPI_AllocateMemory ( (*theCGIHdl)->wsapi, theSize );
- if ( thePtr == NULL )
- {
- if ( outErr != NULL )
- {
- *outErr = memFullErr;
- }
- }
- else
- {
- if ( outErr != NULL )
- {
- *outErr = noErr;
- }
- /* clear the new ptr */
- memset ( thePtr, nil, theSize );
- }
-
- #if kCompileWithExtraQC
- theQCErr = QCBlockBoundsCheckNow ();
- theQCErr = QCHeapCheckNow ();
- #endif
-
- return thePtr;
- } /* CGINewPtrClear */
-
-
- p_export
- void
- CGIDisposeHandle ( CGIHdl theCGIHdl, Handle theHandle )
- {
- my_assert ( theCGIHdl != NULL, "\pCGIDisposeHandle: theCGIHdl is NULL" );
- my_assert ( theHandle != NULL, "\pCGIDisposeHandle: theHandle is NULL" );
-
- WSAPI_FreeOSMemory ( (*theCGIHdl)->wsapi, &theHandle );
- } /* CGIDisposeHandle */
-
-
- p_export
- void
- CGIDisposePtr ( CGIHdl theCGIHdl, Ptr thePtr )
- {
- my_assert ( theCGIHdl != NULL, "\pCGIDisposePtr: theCGIHdl is NULL" );
- my_assert ( thePtr != NULL, "\pCGIDisposePtr: thePtr is NULL" );
-
- WSAPI_FreeMemory ( (*theCGIHdl)->wsapi, thePtr );
- } /* CGIDisposePtr */
-
-
- #endif /* kCompilingForWSAPI */
-
-
- /** FORM FIELDS **/
- #pragma mark -
- #if kCompileWithCGIFormHandling
-
- /* The separator '&' separates individual fields.
- The delimiter '=' delimits the name and value in a field.
- For example: "Field 1=some stuff&Another Field=more stuff&Last Field=no stuff"
- Means that there are 3 fields with names "Field 1", "Another Field" and "Last Field"
-
- The function returns an array of field records with the last containing null values.
-
- You generally shouldn't call this function outside this file.
- Use it at your own risk. */
- /* ••• I should add error reporting */
- p_export
- CGIFormField *
- CGIFormFieldsFromArgs ( CGIHdl theCGIHdl, char *theString, long *count, short *outErr )
- {
- CGIFormField * theFields;
- long totalStrSize;
- long totalFields;
- long nameSize;
- long valueSize;
- long currentField;
- char * theStringPtr;
- char * fieldSeparator;
- char * fieldDelimiter;
- #if kCompileWithExtraQC
- QCErr theQCErr;
- #endif
-
- #if kCompilingForWSAPI
- my_assert ( theCGIHdl != NULL, "\pCGIFormArgs: theCGIHdl is NULL" );
- #endif
- my_assert ( theString != NULL, "\pCGIFormArgs: theString is NULL" );
-
- theFields = NULL;
-
- /* don't return number of fields until function is successful */
- *count = nil;
-
- totalStrSize = strlen ( theString );
-
- /* the total number of fields is the number of separator characters ('&') + 1 */
- totalFields = StringCountChar ( theString, kCGIFormFieldSeparator ) + 1;
- if ( totalFields == 1 )
- {
- /* the case where there were no separator characters is special,
- test for a field delimiter to confirm that the string passed does
- indeed contain field information */
- fieldDelimiter = StringChar ( theString, kCGIFormFieldDelimiter );
- if ( fieldDelimiter == NULL )
- {
- /* string does not contain field data */
- *outErr = 1; /* • might need better error here */
-
- goto Exit_Fail;
- }
- }
-
- theFields = (CGIFormField *) CGINewPtr ( theCGIHdl, ((totalFields + 1) * sizeof(CGIFormField)), outErr );
- if ( theFields == NULL )
- {
- /* memory didn't allocate */
- goto Exit_Fail;
- }
-
- /* set the name and value of the last field in the array to NULL */
- (theFields[totalFields]).name = NULL;
- (theFields[totalFields]).value = NULL;
-
- theStringPtr = theString;
-
- for ( currentField = nil; currentField < totalFields; currentField++ )
- {
- /* set the name and value of the current field in the array to nil.
- this is to handle errors. */
- (theFields[currentField]).name = NULL;
- (theFields[currentField]).value = NULL;
-
- fieldDelimiter = StringChar ( theStringPtr, kCGIFormFieldDelimiter );
- fieldSeparator = StringChar ( theStringPtr, kCGIFormFieldSeparator );
-
- /* if there is a field delimiter, and it is before any field separator */
- if ( (fieldDelimiter != NULL) && ((fieldSeparator > fieldDelimiter) ||
- (fieldSeparator == NULL)) )
- {
- /* field name */
- /* the size of the name string is the difference between the begining
- of the field and the position of the field delimiter */
- nameSize = fieldDelimiter - theStringPtr;
-
- /* allocate the name string */
- (theFields[currentField]).name = (char *) CGINewPtr ( theCGIHdl, nameSize + 1, outErr );
- if ( (theFields[currentField]).name == NULL )
- {
- /* memory didn't allocate */
- (theFields[currentField]).value = NULL;
-
- goto Exit_Fail;
- }
-
- /* copy the field name */
- BlockMove ( theStringPtr, (theFields[currentField]).name, nameSize );
- /* null terminate the end of the name string */
- ((theFields[currentField]).name)[nameSize] = nil;
- /* convert the url encoded text to a normal string */
- CGIDecodeURLChars ( (theFields[currentField]).name );
-
- /* field value */
- if ( fieldSeparator != NULL )
- {
- valueSize = fieldSeparator - (fieldDelimiter + 1);
- }
- else
- {
- valueSize = strlen ( fieldDelimiter + 1 );
- }
-
- (theFields[currentField]).value = (char *) CGINewPtr ( theCGIHdl, (valueSize + 1), outErr );
- if ( (theFields[currentField]).value == NULL )
- {
- /* memory didn't allocate */
- CGIDisposePtr ( theCGIHdl, (theFields[currentField]).name );
- (theFields[currentField]).name = NULL;
-
- goto Exit_Fail;
- }
-
- BlockMove ( fieldDelimiter + 1, (theFields[currentField]).value, valueSize );
- ((theFields[currentField]).value)[valueSize] = nil;
- CGIDecodeURLChars ( (theFields[currentField]).value );
-
- theStringPtr = fieldSeparator + 1;
- }
- else
- {
- /* invalid data encountered */
- *outErr = 2; /* •• need better error value */
-
- goto Exit_Fail;
- }
- }
-
- /* assign the return parameters values */
- *count = totalFields;
- *outErr = noErr;
-
- #if kCompileWithExtraQC
- theQCErr = QCBlockBoundsCheckNow ();
- #endif
-
- return theFields;
-
-
- Exit_Fail:
-
- if ( theFields != NULL )
- {
- /* release allocated memory */
- CGIFormFieldsDispose ( theCGIHdl, theFields );
- }
-
- #if kCompileWithExtraQC
- theQCErr = QCBlockBoundsCheckNow ();
- theQCErr = QCHeapCheckNow ();
- #endif
-
- return NULL;
- } /* CGIFormFieldsFromArgs */
-
-
- /* Returns a pointer to the first form field record, in the given fieldArray,
- that's name matches the supplied field name.
- [modified for 1.0b4 - use CGIHdl as parameter instead of CGIFormField] */
- p_export
- CGIFormField *
- CGIFormFieldsFindRecord ( CGIHdl theCGIHdl, const char *fieldName )
- {
- CGIFormField *fieldArray;
- long currentField;
- short stringDifference;
-
- my_assert ( theCGIHdl != NULL, "\pCGIFormFieldsFindRecord: theCGIHdl is NULL" );
- my_assert ( fieldName != NULL, "\pCGIFormFieldsFindRecord: fieldName is NULL" );
-
- fieldArray = (*theCGIHdl)->formFields;
- if ( (*theCGIHdl)->formFields == NULL )
- {
- return NULL;
- }
-
- /* look til we find something or we hit the end */
- for ( currentField = nil; (fieldArray[currentField]).name != NULL; currentField++ )
- {
- stringDifference = strcmp ( (fieldArray[currentField]).name, fieldName );
- if ( stringDifference == nil )
- {
- /* found a match, so we're done */
- return &(fieldArray[currentField]);
- }
- }
-
- /* didn't find a match */
- return NULL;
- } /* CGIFormFieldsFindRecord */
-
-
- /* Returns a pointer to the string containing the value from the field specified
- by 'fieldName'. Returns a pointer to a null string ("") if the field is not
- found. The pointer points directly into the form fields array in theCGIHdl.
- IMPORTANT: Whatever you do - do not attempt to deallocate the string returned
- by this function!!! */
- p_export
- const char *
- CGIFormFieldsFindValue ( CGIHdl theCGIHdl, const char *fieldName )
- {
- CGIFormField * theField;
-
- my_assert ( theCGIHdl != NULL, "\pCGIFormFieldsFindValue: theCGIHdl is NULL" );
- my_assert ( fieldName != NULL, "\pCGIFormFieldsFindValue: fieldName is NULL" );
-
- theField = CGIFormFieldsFindRecord ( theCGIHdl, fieldName );
- if ( (theField == NULL) || (theField->value == NULL) )
- {
- return vNULLString;
- }
- else
- {
- return theField->value;
- }
- } /* CGIFormFieldsFindValue */
-
-
- /* Deallocate memory for theFields array.
- You generally shouldn't call this function outside this file.
- Use it at your own risk. */
- void
- CGIFormFieldsDispose ( CGIHdl theCGIHdl, CGIFormField *theFields )
- {
- long offset;
-
- #if kCompilingForWSAPI
- my_assert ( theCGIHdl != NULL, "\pCGIFormFieldsDispose: theCGIHdl is NULL" );
- #else
- #pragma unused(theCGIHdl)
- #endif
- my_assert ( theFields != NULL, "\pCGIFormFieldsDispose: theFields is NULL" );
-
- offset = nil;
-
- do
- {
- if ( (theFields[offset]).name != NULL )
- {
- /* if there's a name string, deallocate its memory */
- CGIDisposePtr ( theCGIHdl, (Ptr)((theFields[offset]).name) );
-
- if ( (theFields[offset]).value != NULL )
- {
- /* if there's a value string, deallocate its memory */
- CGIDisposePtr ( theCGIHdl, (Ptr)((theFields[offset]).value) );
- }
- }
-
- offset++;
- } while ( (theFields[offset]).name != NULL );
-
- CGIDisposePtr ( theCGIHdl, (Ptr)theFields );
- } /* CGIFormFieldsDispose */
-
- #endif /* kCompileWithCGIFormHandling */
-
-
- /** UTILITIES **/
- #pragma mark -
-
- #if kCompileWithCGIActionSupport
- /* Returns true if the action parameter is either CGI or ACGI.
- Returns false if it is some other action. */
- p_export
- Boolean
- CGIActionIsCGIorACGI ( CGIHdl theCGIHdl )
- {
- int stringDifference;
-
- my_assert ( theCGIHdl != NULL, "\pCGIActionIsCGIorACGI: theCGIHdl is NULL" );
-
- if ( ((*theCGIHdl)->action)[0] == nil )
- {
- /* if no action is specified, default to CGI as action */
- return true;
- }
-
- /* is the action "CGI"? */
- stringDifference = strcmp ( (*theCGIHdl)->action, kCGIActionNameCGI );
- if ( stringDifference == nil )
- {
- return true;
- }
-
- /* is the action "ACGI"? */
- stringDifference = strcmp ( (*theCGIHdl)->action, kCGIActionNameACGI );
- if ( stringDifference == nil )
- {
- return true;
- }
-
- /* didn't find a match */
- return false;
- } /* CGIActionIsCGIorACGI */
- #endif /* kCompileWithCGIActionSupport */
-
-
- /* Test a given path string to ensure it won't try to 'jump' levels.
- thePathString must not be URL encoded (specifically, no %xx hex encoding). */
- p_export
- Boolean
- CGIIsSecurePath ( char *thePathString )
- {
- UInt16 currentChar;
-
- my_assert ( thePathString != NULL, "\pCGIIsSecurePath: thePathString is NULL" );
-
- switch ( thePathString[0] )
- {
- case '\0' :
- /* empty string - no security problem */
- return true;
- break;
-
- case '/' :
- case ':' :
- if ( (thePathString[1] == '/') || (thePathString[1] == ':') )
- {
- /* string begins with '//' or '::' or ':/' or '/:' */
- return false;
- }
- break;
-
- case '.' :
- if ( (thePathString[1] == '.') &&
- ((thePathString[2] == '/') || (thePathString[2] == ':')) )
- {
- /* string begins with '../' or '..:' */
- return false;
- }
- break;
-
- default :
- break;
- }
-
- currentChar = 1;
-
- while ( thePathString[currentChar] != '\0' )
- {
- switch ( thePathString[currentChar] )
- {
- case '/' :
- case ':' :
- if ( (thePathString[currentChar+1] == '/') || (thePathString[currentChar+1] == ':') )
- {
- /* string contains '//' or '::' or ':/' or '/:' */
- return false;
- }
- break;
-
- case '.' :
- if ( (thePathString[currentChar+1] == '.') &&
- ((thePathString[currentChar-1] == '/') || (thePathString[currentChar-1] == ':')) &&
- ((thePathString[currentChar+2] == '/') || (thePathString[currentChar+2] == ':')) )
- {
- /* string contains '/../' or ':..:' or some such */
- return false;
- }
- break;
-
- default :
- break;
- }
-
- currentChar++;
- }
-
- /* no security leaks encountered */
- return true;
- } /* CGIIsSecurePath */
-
-
- /* Check to see if the client accessed the server with the correct host name.
- This is only useful for browsers that include the "Host:" field in their
- HTTP request. If no host field is found, (or if the server did not
- supply the full_request data) this function will default to returning
- false (no difference). */
- #if kCompileWithCGIfull_request
- p_export
- Boolean
- CGIHostNameDifferent ( CGIHdl theCGIHdl, char *theHostName, short hostNameLength )
- {
- char * hostLine;
- int stringDiff;
-
- my_assert ( theCGIHdl != NULL, "\pCGIHostNameDifferent: theCGIHdl is NULL" );
- my_assert ( theHostName != NULL, "\pCGIHostNameDifferent: theHostName is NULL" );
-
- /* confirm that the full_request is available */
- if ( ((*theCGIHdl)->full_request == NULL) || (((*theCGIHdl)->full_request)[nil] == nil) )
- {
- /* can't check, so just let client pass */
- return false;
- }
-
- /* search full_request for the Host: field */
- hostLine = strstr ( (*theCGIHdl)->full_request, "\r\nHost: " );
- if ( hostLine == NULL )
- {
- /* can't check, so just let client pass */
- return false;
- }
-
- /* move the ptr to the begining of the host data */
- hostLine += 8;
-
- /* check to see if the Host: field matches */
- stringDiff = strncmp ( hostLine, theHostName, hostNameLength );
-
- return (stringDiff != nil);
- } /* CGIHostNameDifferent */
- #endif
-
-
- /* This is just a preliminary logging function that will log all the data from the cgi */
- p_export
- void
- CGILogData ( CGIHdl theCGIHdl )
- {
- #if kCompileWithCGIserver_port || kCompileWithCGISendPartial || kCompileWithCGIFormHandling
- char tempStr[256];
- #endif
- #if kCompileWithCGIFormHandling
- long counter;
- #endif
- #if kCompileWithExtraQC
- QCErr theQCErr;
- #endif
-
- LogStringBreakP ( "\p=== CGI PARAMETERS ===" );
-
- #if kCompileWithCGIpath_args
- if ( (*theCGIHdl)->path_args != NULL )
- {
- LogString ( "path_args:" );
- LogStringBreak ( (*theCGIHdl)->path_args );
- }
- #endif
-
- #if kCompileWithCGIhttp_search_args
- if ( (*theCGIHdl)->http_search_args != NULL )
- {
- LogString ( "http_search_args:" );
- LogStringBreak ( (*theCGIHdl)->http_search_args );
- }
- #endif
-
- #if kCompileWithCGIusername
- LogString ( "username:" );
- LogStringBreak ( (*theCGIHdl)->username );
- #endif
-
- #if kCompileWithCGIpassword
- if ( (*theCGIHdl)->password != NULL )
- {
- LogString ( "password:" );
- LogStringBreak ( (*theCGIHdl)->password );
- }
- #endif
-
- #if kCompileWithCGIfrom_user
- if ( (*theCGIHdl)->from_user != NULL )
- {
- LogString ( "from_user:" );
- LogStringBreak ( (*theCGIHdl)->from_user );
- }
- #endif
-
- #if kCompileWithCGIclient_address
- if ( (*theCGIHdl)->client_address != NULL )
- {
- LogString ( "client_address:" );
- LogStringBreak ( (*theCGIHdl)->client_address );
- }
- #endif
-
- #if kCompileWithCGIpost_args
- if ( (*theCGIHdl)->post_args != NULL )
- {
- LogString ( "post_args:" );
- LogStringBreak ( (*theCGIHdl)->post_args );
- }
- #endif
-
- #if kCompileWithCGImethod
- LogString ( "method:" );
- switch ( (*theCGIHdl)->method )
- {
- case HTTP_get :
- LogStringBreak ( kCGIHTTPMethodGet );
- break;
-
- case HTTP_post :
- LogStringBreak ( kCGIHTTPMethodPost );
- break;
-
- case HTTP_getConditional :
- LogStringBreak ( kCGIHTTPMethodGetConditional );
- break;
-
- default :
- LogStringBreak ( "<undefined>" );
- break;
- }
- #endif
-
- #if kCompileWithCGIserver_name
- if ( (*theCGIHdl)->server_name != NULL )
- {
- LogString ( "server_name:" );
- LogStringBreak ( (*theCGIHdl)->server_name );
- }
- #endif
-
- #if kCompileWithCGIserver_port
- LogString ( "server_port:" );
- sprintf ( tempStr, "%d", (*theCGIHdl)->server_port );
- LogStringBreak ( tempStr );
- #endif
-
- #if kCompileWithCGIscript_name
- if ( (*theCGIHdl)->script_name != NULL )
- {
- LogString ( "script_name:" );
- LogStringBreak ( (*theCGIHdl)->script_name );
- }
- #endif
-
- #if kCompileWithCGIcontent_type
- if ( (*theCGIHdl)->content_type != NULL )
- {
- LogString ( "content_type:" );
- LogStringBreak ( (*theCGIHdl)->content_type );
- }
- #endif
-
- #if kCompileWithCGIreferer
- if ( (*theCGIHdl)->referer != NULL )
- {
- LogString ( "referer:" );
- LogStringBreak ( (*theCGIHdl)->referer );
- }
- #endif
-
- #if kCompileWithCGIuser_agent
- if ( (*theCGIHdl)->user_agent != NULL )
- {
- LogString ( "user_agent:" );
- LogStringBreak ( (*theCGIHdl)->user_agent );
- }
- #endif
-
- #if kCompileWithCGIActionSupport
- LogString ( "action:" );
- LogStringBreak ( (*theCGIHdl)->action );
- if ( (*theCGIHdl)->action_path != NULL )
- {
- LogString ( "action_path:" );
- LogStringBreak ( (*theCGIHdl)->action_path );
- }
- #endif
-
- #if kCompileWithCGIclient_ip
- LogString ( "client_ip:" );
- LogStringBreak ( (*theCGIHdl)->client_ip );
- #endif
-
- #if kCompileWithCGIfull_request
- if ( (*theCGIHdl)->full_request != NULL )
- {
- LogString ( "full_request:" );
- LogStringBreak ( (*theCGIHdl)->full_request );
- }
- #endif
-
- #if kCompileWithCGISendPartial
- LogString ( "connection:" );
- sprintf ( tempStr, "%d", (*theCGIHdl)->connection );
- LogStringBreak ( tempStr );
- #endif
-
- #if kCompileWithCGIFormHandling
- LogString ( "totalFields:" );
- sprintf ( tempStr, "%d", (*theCGIHdl)->totalFields );
- LogStringBreak ( tempStr );
-
- if ( (*theCGIHdl)->totalFields > nil )
- {
- LogStringBreak ( "formFields:" );
- for ( counter = 0; counter < (*theCGIHdl)->totalFields; counter++ )
- {
- LogStringP ( "\p\t" ); /* put a tab character at the begining */
- LogStringAndSeparator ( (((*theCGIHdl)->formFields)[counter]).name, '\t' );
- LogStringBreak ( (((*theCGIHdl)->formFields)[counter]).value );
- }
- }
- #endif
-
- LogStringBreakP ( "\p=== end cgi parameters ===" );
-
- #if kCompileWithExtraQC
- theQCErr = QCBlockBoundsCheckNow ();
- theQCErr = QCHeapCheckNow ();
- #endif
- } /* CGILogData */
-
-
- /** CHARACTER CODING **/
- #pragma mark -
-
- /* replaces instances of percent signs (%) followed by an ASCII char value
- with the actual character.
- This function modifies theString parameter! */
- p_export
- void
- CGIDecodeURLChars ( char *theString )
- {
- UInt32 read;
- UInt32 write;
- unsigned char theChar;
- unsigned char highOrder;
- unsigned char lowOrder;
- Boolean isValid;
-
- my_assert ( theString != NULL, "\pCGIDecodeURLChars: NULL string" );
-
- read = nil;
- write = nil;
-
- while ( theString[read] != nil )
- {
- switch ( theString[read] )
- {
- case '%':
- /* a percent symbol begins a hex char block (%## where ## is the hex value) */
-
- isValid = true;
-
- /* determine high order hex character */
- if ( (theString[read+1] >= 'A') && (theString[read+1] <= 'F') )
- {
- /* uppercase A-F convert to 10-15 */
- highOrder = theString[read+1] - 'A' + 10;
- }
- else if ( (theString[read+1] >= 'a') && (theString[read+1] <= 'f') )
- {
- /* lowercase a-f convert to 10-15 */
- highOrder = theString[read+1] - 'a' + 10;
- }
- else if ( (theString[read+1] >= '0') && (theString[read+1] <= '9') )
- {
- /* character digits 0-9 convert to decimal 0-9 */
- highOrder = theString[read+1] - '0';
- }
- else
- {
- /* Illegal character! Can't convert from hex */
- isValid = false;
- }
-
- /* Multiply high order hex digit by 16 */
- highOrder *= 16;
-
- /* determine low order hex character */
- if ( (theString[read+2] >= 'A') && (theString[read+2] <= 'F') )
- {
- /* uppercase A-F convert to 10-15 */
- lowOrder = (theString[read+2] - 'A' + 10);
- }
- else if ( (theString[read+2] >= 'a') && (theString[read+2] <= 'f') )
- {
- /* lowercase a-f convert to 10-15 */
- lowOrder = (theString[read+2] - 'a' + 10);
- }
- else if ( (theString[read+2] >= '0') && (theString[read+2] <= '9') )
- {
- /* character digits 0-9 convert to decimal 0-9 */
- lowOrder = (theString[read+2] - '0');
- }
- else
- {
- /* Illegal character! Can't convert from hex */
- isValid = false;
- }
-
- theChar = highOrder + lowOrder;
-
- if ( isValid )
- {
- isValid = (theChar >= 0) && (theChar < 256);
- }
-
- if ( isValid )
- {
- /* if theChar is valid, write it out */
-
- if ( theChar == 10 )
- {
- /* don't write newline */
- write--;
- }
- else
- {
- theString[write] = theChar;
- }
-
- /* Increment read past the two digits of the hex code */
- read += 2;
- }
- else
- {
- /* invalid hex character code, just write out the percent symbol */
- theString[write] = theString[read];
- }
- break;
-
- case '+':
- /* Plus symbols convert to space */
- theString[write] = ' ';
- break;
-
- case 10:
- /* ignore line feeds, we only need carriage returns (13) */
- write--;
- break;
-
- default:
- /* write out the character */
- theString[write] = theString[read];
- break;
- }
-
- read++;
- write++;
- }
-
- /* terminate the string */
- theString[write] = '\0';
- } /* CGIDecodeURLChars */
-
-
- /* • UPDATE 1996-03-10 •
- %hex encode all non-alphanumeric characters. IE. '~' (126) becomes '%7E'
- theString parameter is not modified.
- Will return NULL if unable to allocate memory for the encoded string.
- outErr will not be set if it is a NULL ptr. */
- p_export
- char *
- CGIEncodeURLChars ( CGIHdl theCGIHdl, const char *theString, OSErr *outErr )
- {
- char * theResult; /* new string containing the encoded form of theString */
- long strSize; /* size of the source string */
- Boolean charNeedsToBeHex; /* char needs to be encoded as hex */
- const char * stringLoc; /* current location in theString */
- char * resultLoc; /* current location in theResult string */
- #if kCompileWithExtraQC
- QCErr theQCErr;
- #endif
-
- #if kCompilingForWSAPI
- my_assert ( theCGIHdl != NULL, "\pCGIEncodeURLChars: theCGIHdl is NULL" );
- #else
- #pragma unused(theCGIHdl)
- #endif
- my_assert ( theString != NULL, "\pCGIEncodeURLChars: theString is NULL" );
-
- /* loop through the string finding out how big our final string will need to be.
- Add two extra bytes for every 'special' character. */
- strSize = nil;
- for ( stringLoc = theString; *stringLoc != nil; stringLoc++ )
- {
- charNeedsToBeHex = CGICharWillHex ( *stringLoc );
- if ( charNeedsToBeHex )
- {
- /* the character at strOffset is alpha-numeric */
- strSize++;
- }
- else
- {
- /* the character at strOffset is special (not alpha-numeric) */
- strSize += 3;
- }
- }
-
- /* allocate space for the new encoded string */
- theResult = (char *) CGINewPtr ( theCGIHdl, (strSize + 1), outErr );
- if ( theResult != NULL )
- {
- /* encode theString into the new encoded string (theResult).
- loop through the characters of the old string,
- copying the alpha-numeric chars to the new string,
- but copying in %XX encoded form when non-alpha-numeric. */
- for ( stringLoc = theString, resultLoc = theResult; *stringLoc != nil; stringLoc++, resultLoc++ )
- {
- charNeedsToBeHex = CGICharWillHex ( *stringLoc );
- if ( charNeedsToBeHex )
- {
- /* if the character is alphanumeric just copy it */
- *resultLoc = *stringLoc;
- }
- else
- {
- /* if the character is not alphanumeric, hex encode it */
- CGICharToHex ( *stringLoc, resultLoc );
- /* add the extra two characters for hex encoding to the result offset */
- resultLoc += 2;
- }
- }
-
- /* terminate the string after the last character written */
- *resultLoc = nil;
- }
-
- #if kCompileWithExtraQC
- theQCErr = QCBlockBoundsCheckNow ();
- theQCErr = QCHeapCheckNow ();
- #endif
-
- return theResult;
- } /* CGIEncodeURLChars */
-
-
- /* returns true if theChar will be converted to hex when encoding as an URL string */
- p_export
- Boolean
- CGICharWillHex ( unsigned char theChar )
- {
- return (
- ((theChar >= 'a') && (theChar <= 'z')) || /* 0x60 - 0x7A; a-z */
- ((theChar >= '?') && (theChar <= 'Z')) || /* 0x3F - 0x5A; ? @ A-Z */
- ((theChar >= '-') && (theChar <= ':')) || /* 0x2D - 0x3A; - . / 0-9 : */
- ((theChar >= '\"') && (theChar <= '$')) || /* 0x22 - 0x24; " # $ */
- (theChar == '&') || (theChar == '\'') || /* 0x26 0x27; & ' */
- (theChar == '=') ); /* 0x3D; = */
- } /* CGICharWillHex */
-
-
- /* Converts theChar to percent-hex encoding for URLs, and writes that to theString.
- This assumes that theString is at least 4 bytes long (to have enough room to
- write the hex encoded text). */
- p_export
- void
- CGICharToHex ( unsigned char theChar, char *theString )
- {
- unsigned char chrChunk;
-
- /* start off with a percent symbol to indicate a hex character code */
- theString[0] = '%';
-
- /* mask to get the high 4 bits, then shift them into the lower 4 bits */
- chrChunk = (theChar & 0xF0) >> 4;
- if ( chrChunk > 9 )
- {
- /* chrChunk is a value between A and F in hex */
- theString[1] = (chrChunk - 10) + 'A';
- }
- else
- {
- /* chrChunk is a value between 0 and 9 in hex */
- theString[1] = chrChunk + '0';
- }
-
- /* mask to get the low 4 bits */
- chrChunk = theChar & 0x0F;
- if ( chrChunk > 9 )
- {
- /* chrChunk is a value between A and F in hex */
- theString[2] = (chrChunk - 10) + 'A';
- }
- else
- {
- /* chrChunk is a value between 0 and 9 in hex */
- theString[2] = chrChunk + '0';
- }
- } /* CGICharToHex */
-
-
- /* convert a '/' delimited path to a ':' delimited one, and make sure there's
- one ':' at the start if the path includes folders.
- This function may modify ioPathString.
- ioPathString MUST have an extra byte after its terminating null byte. */
- p_export
- void
- CGIPathToMacPath ( char *ioPathString )
- {
- char * theWorkString;
- char * theSlashOffset;
-
- /* we start with a directory marker, so we won't need to add one. */
- if ( (ioPathString[0] == '/') || (ioPathString[0] == ':') )
- {
- StringConvertCharToChar ( ioPathString, '/', ':' );
- }
- else
- {
- /* check if there are any slashes */
- theSlashOffset = strchr ( ioPathString, '/' );
- if ( theSlashOffset == NULL )
- {
- /* there are no slashes, so nothing no change is needed. */
- }
- else
- {
- /* find the terminating null byte at the end of the string */
- theWorkString = strchr ( ioPathString, '\0' );
- while ( theWorkString >= ioPathString )
- {
- /* the char following the current one is written as a colon if
- this one is a slash, or has this char written to it */
- theWorkString[1] = (theWorkString[0] == '/')? ':' : theWorkString[0];
- theWorkString--;
- }
-
- /* make sure there is a leading colon for the path */
- ioPathString[0] = ':';
- }
- }
- } /* CGIPathToMacPath */
-
-
- /*** SENDING DATA ***/
- #pragma mark -
-
- /* •new• This function can be used within the context of CustomCGIProcess only.
- It should be used if you want to return data to the client before you
- finish processing (especially if processing will take a while), or if you
- are doing a server-push operation (multipart documents).
- theCGIHdl's replyData will still be sent upon completion, unless it is null.
- If you get an error from this function, you can send no more data so should
- halt processing.
-
- If you are compiling as a CGI application, this will implement Send Partial.
-
- WARNING: Send Partial support is BUGGY! Fixing it is very high on my list
- of priorities for the framework.
- */
- p_export
- OSErr
- CGISendData ( CGIHdl theCGIHdl, void *theData, long dataSize, Boolean sendMore )
- {
- SInt16 theErr; /* WSAPI_ErrorCode or OSErr */
- #if kCompileWithExtraQC
- QCErr theQCErr;
- #endif
-
- #if kCompilingForWSAPI
- #pragma unused(sendMore)
-
- theErr = WSAPI_SendHTTPData ( (*theCGIHdl)->wsapi, theData, dataSize );
- if ( (theErr == WSAPI_I_NoErr) && !((*theCGIHdl)->dataSent) )
- {
- /* set dataSent so that we'll know that SendData has been used and we
- won't return an http error header to the client if replyData is
- null when the CustomCGIProcess function returns. */
- (*theCGIHdl)->dataSent = true;
- }
-
- #elif kCompileWithCGISendPartial
-
- theErr = noErr;
-
- if ( !((*theCGIHdl)->sendPartialActive) )
- {
- /* theCGIHdl hasn't been used to Send Partial yet - need to start
- a send partial transaction with the web server */
- theErr = cgiAESendPartialStart ( theCGIHdl, (char *)theData, dataSize );
- if ( theErr == noErr )
- {
- (*theCGIHdl)->sendPartialActive = true;
- }
- }
-
- if ( theErr == noErr )
- {
- theErr = cgiAESendPartial ( theCGIHdl, (char *)theData, dataSize, sendMore );
- }
-
- if ( !(sendMore) )
- {
- (*theCGIHdl)->sendPartialDone = true;
- }
-
- #else
-
- #pragma unused(theCGIHdl,theData,dataSize,sendMore)
-
- /* CGISendData should not be called unless kCompilingForWSAPI or
- kCompileWithCGISendPartial */
- theErr = true;
-
- #endif
-
- #if kCompileWithExtraQC
- theQCErr = QCBlockBoundsCheckNow ();
- theQCErr = QCHeapCheckNow ();
- #endif
-
- return theErr;
- } /* CGISendData */
-
-
- #if kCompileWithCGISendPartial && !kCompilingForWSAPI
-
- /* From the WebSTAR 1.2 addendum:
-
- An ACGI has to inform the WebSTAR server that it intends to
- return its results in pieces over a period of time, rather than
- simply lumping it all into the value returned from the WWWWsdoc
- event. WebSTAR examines the results from an ACGI's reply to see
- if it matches the string:
-
- <SEND_PARTIAL>
-
- If this 14 character string is matched exactly (case sensitive),
- then WebSTAR doesn’t send anything to the client and keeps the
- connection open until the timeout period expires or WebSTAR
- receives data via the Send Partial event for that connection.
-
- Send Partial events received before the <SEND_PARTIAL> response
- to the sdoc event are also a legal way to indicate that server push
- functions are to be performed for a given connection.
-
- As long as Send Partial events are received for a given
- connection, the timeout timer is restarted and the data is sent
- to the client. If the Send Partial event’s “more” parameter is
- FALSE, the server closes the connection and assumes that the
- ACGI has finished sending data.
-
- To send events back to WebSTAR from a language like C or Pascal,
- you must extract and save the “from” Apple event attribute from
- the reply event sent to your WWWWsdoc handler. The “from” event
- contains the AEAddressDesc used to address the “SPar” events to
- WebSTAR.
-
- Here's the general flow of events
-
- 1. A WWW client sends an ACGI URL request to WebSTAR.
-
- 2. WebSTAR sends a WWWWsdoc event to the ACGI, passing the
- connection ID.
-
- 3. The ACGI decides it needs to return data in pieces, so it
- replies to the sdoc event with the string <SEND_PARTIAL> and
- saves the connection ID.
-
- 4. WebSTAR sees that the ACGI wants to return partial data, so
- it sets a flag indicating that the connection should be checked
- periodically for timeouts and resets the timer.
-
- 5. The ACGI sends a Send Partial event to WebSTAR with the first
- chunk of data, the connection ID, and the “more” flag set to
- TRUE, indicating more data to come.
-
- 6. WebSTAR handles the Send Partial event, finds the requested
- connection, and queues up the data for transmission to the
- client (allowing the thread owning the connection to schedule
- the transmission.) WebSTAR then resets the time-out for the
- connection.
-
- Steps 5 and 6 repeat at whatever interval the client decides
- until the “more” parameter is false. WebSTAR receives the final
- Send Partial event with the “more” flag set to false, sends the
- accompanying data, and closes the client connection. */
-
- /* The connection ID is found in theCGIHdl as the 'connection' field.
- Connection is used to identify the particular connection on which to send
- the data.
- The data to be sent is pointed to by theData, which is dataSize bytes long.
- If sendMore is true, there is more data to be sent after processing this
- event. If it is false, the server will terminate the connection after
- sending the data from this event.
- theCGIHdl should not be locked when it is passed to this function.
- */
- #pragma segment AppleEvents
- p_export
- OSErr
- cgiAESendPartial ( CGIHdl theCGIHdl, char *theData, long dataSize, Boolean sendMore )
- {
- OSErr theErr;
- DescType descApp;
- AEAddressDesc targetAddress;
- AppleEvent theAppleEvent;
- AppleEvent reply;
- short errNum;
- DescType returnedType;
- long actualSize;
- #if kCompileWithExtraQC
- QCErr theQCErr;
- #endif
-
- my_assert ( theCGIHdl != NULL, "\pcgiAESendPartial: theCGIHdl is NULL" );
- my_assert ( theData != NULL, "\pcgiAESendPartial: theData is NULL" );
-
- //••• need to change this to /* use the process ID from the server */
- /* create the application descriptor */
- descApp = kAEClassCGI;
- theErr = AECreateDesc ( typeApplSignature, &descApp, sizeof(DescType),
- &targetAddress );
- if ( theErr != noErr )
- {
- goto EXIT_AESEND;
- }
-
- /* create the apple event record */
- theErr = AECreateAppleEvent ( kAEClassCGI, kMyAESendPartial, &targetAddress,
- kAutoGenerateReturnID, kAnyTransactionID, &theAppleEvent );
- if ( theErr != noErr )
- {
- goto EXIT_AESEND;
- }
-
- /* put the data */
- theErr = AEPutParamPtr ( &theAppleEvent, kCGIPartialData, typeChar,
- theData, dataSize );
- if ( theErr != noErr )
- {
- goto EXIT_AESEND;
- }
-
- my_assert ( (HGetState((Handle)theCGIHdl) & kMemoryHandleLockedFlag) == nil,
- "\pcgiAESendPartial: theCGIHdl is already locked!" );
- HLockHi ( (Handle)theCGIHdl );
- /* put the connection id */
- theErr = AEPutParamPtr ( &theAppleEvent, kConnectionIDKeyword, typeLongInteger,
- &((*theCGIHdl)->connection), sizeof(long) );
- if ( theErr != noErr )
- {
- goto EXIT_AESEND;
- }
- HUnlock ( (Handle)theCGIHdl );
-
- /* put the more value */
- theErr = AEPutParamPtr ( &theAppleEvent, kMoreKeyword, typeBoolean, &sendMore,
- sizeof(Boolean) );
- if ( theErr != noErr )
- {
- goto EXIT_AESEND;
- }
-
- /* send the apple event */
- //••• what to do when reply is delayed?
- theErr = AESend ( &theAppleEvent, &reply, kAEWaitReply + kAENeverInteract /*5-14*/,
- kAENormalPriority, kAEMyTimeoutInTicks, gAEIdleUPP, NULL );
- if ( theErr != noErr )
- {
- goto EXIT_AESEND;
- }
-
- /* extract the error reply */
- errNum = noErr;
- theErr = AEGetParamPtr ( &reply, keyErrorNumber, typeSMInt, &returnedType, &errNum,
- sizeof(errNum), &actualSize );
- if ( (theErr != noErr) && (theErr != errAEDescNotFound) )
- {
- goto EXIT_AESEND;
- }
-
- theErr = errNum;
-
- EXIT_AESEND:
-
- AEDisposeDesc ( &targetAddress );
- AEDisposeDesc ( &theAppleEvent );
- //••• should the reply AppleEvent be disposed of here, too???
-
- #if kCompileWithExtraQC
- theQCErr = QCBlockBoundsCheckNow ();
- theQCErr = QCHeapCheckNow ();
- #endif
-
- return theErr;
- } /* cgiAESendPartial */
-
-
- /* ••• */
- p_export
- OSErr
- cgiAESendPartialStart ( CGIHdl theCGIHdl, char *theData, long dataSize )
- {
- #pragma unused (theCGIHdl,theData,dataSize)
-
- OSErr theErr;
-
- theErr = noErr;
-
- return theErr;
- } /* cgiAESendPartialStart */
-
-
- #endif /* kCompileWithCGISendPartial && !kCompilingForWSAPI */
-
-
- /* ••• This function is incomplete - don't use it!!! */
- p_export
- OSErr
- CGIPassAppleEvent ( CGIHdl theCGIHdl, OSType destinationOSCreator )
- {
- OSErr theErr;
- AEAddressDesc theAEAddress;
- AppleEvent theAppleEvent;
-
- my_assert ( theCGIHdl != NULL, "\pCGIPassAppleEvent: theCGIHdl is NULL" );
- #if !(kCompileWithAssertions)
- #pragma unused(theCGIHdl)
- #endif
-
- theErr = AECreateDesc ( typeApplSignature, &destinationOSCreator, sizeof(OSType), &theAEAddress );
-
- theErr = AECreateAppleEvent ( 'WWWΩ', 'sdoc', &theAEAddress, kAutoGenerateReturnID, kAnyTransactionID, &theAppleEvent );
-
- // ••• This function is incomplete - don't use it!!!
-
- return theErr;
- } /* CGIPassAppleEvent */
-
-
- /** WebSTAR API SUPPORT **/
- #pragma mark -
- #if kCompilingForWSAPI
-
- /* Returns the data for a specific parameter.
- If buffer is NULL, it will be allocated.
- buffer is returned if it is passed as non-NULL.
- bufferSize must be the size in bytes of buffer if it is non-NULL. */
- p_export char *
- CGIWSAPIGetParam ( WSAPI_CommandPBPtr commandPtr, WSAPI_ParamKeywords which,
- void *buffer, UInt32 bufferSize )
- {
- WSAPI_DescPtr theDesc;
- OSType dtype;
- UInt32 dataSize;
- WSAPI_ErrorCode err;
- char msgString[32];
- char * newBuffer;
- #if kCompileWithExtraQC
- QCErr theQCErr;
- #endif
-
- theDesc = NULL;
- newBuffer = NULL;
-
- if ( buffer != NULL )
- {
- my_assert ( bufferSize > nil, "\pCGIWSAPIGetParam: buffer is not NULL, but bufferSize < 1" );
-
- ((char*)buffer)[0] = '\0';
- }
-
- /* get the parameter descriptor from the server */
- err = WSAPI_GetParameter ( commandPtr, which, &theDesc );
- if ( err != WSAPI_I_NoErr )
- {
- WSAPI_DisplayMessage ( commandPtr, "PLUGIN: Error getting parameter" );
- }
- else
- {
- /* find out how big the data is */
- dataSize = nil;
- err = WSAPI_GetDescriptor ( commandPtr, theDesc, &dtype, NULL, &dataSize );
- if ( err == WSAPI_I_NoErr )
- {
- if ( buffer == NULL )
- {
- if (dataSize > nil)
- {
- /* we need to allocate the buffer based on the size returned.
- This is a special case where we make a direct call to the WSAPI. */
- newBuffer = (char *) WSAPI_AllocateMemory ( commandPtr, dataSize + 1 );
- if ( newBuffer != NULL )
- {
- /* copy the data into the newBuffer */
- err = WSAPI_GetDescriptor ( commandPtr, theDesc, &dtype, newBuffer, &dataSize );
- if ( err != WSAPI_I_NoErr )
- {
- /* This is a special case where we make a direct call to the WSAPI. */
- WSAPI_FreeMemory ( commandPtr, newBuffer );
- newBuffer = NULL;
- }
- }
- else
- {
- err = (WSAPI_ErrorCode)memFullErr;
- }
- }
- else
- {
- /* no data in parameter, so don't bother allocating a buffer */
- newBuffer = NULL;
- }
- }
- else
- {
- if ( dataSize == nil )
- {
- /* no data in parameter, so don't bother copying it to the buffer */
- ((char *)buffer)[0] = nil;
- newBuffer = NULL;
- }
- else if ( bufferSize < dataSize )
- {
- /* error: the data is too big for the supplied buffer */
- err = WSAPI_E_DescriptorTooSmall;
- }
- else
- {
- /* copy the data into the buffer */
- dataSize = bufferSize;
- err = WSAPI_GetDescriptor ( commandPtr, theDesc, &dtype, buffer, &dataSize );
- /* we're going to return the buffer */
- newBuffer = (char *) buffer;
- }
- }
- }
-
- if ( err != WSAPI_I_NoErr )
- {
- WSAPI_DisplayMessage ( commandPtr, "PLUGIN: Error getting data from descriptor" );
- }
- else if ( newBuffer != NULL )
- {
- if ( dtype == typeChar )
- {
- /* text data, make sure it is terminated */
- newBuffer[dataSize] = '\0';
- }
- }
-
- err = WSAPI_DisposeDescriptor ( commandPtr, &theDesc );
- if ( err != WSAPI_I_NoErr )
- {
- sprintf ( msgString, "Dispose error %d", err );
- WSAPI_DisplayMessage ( commandPtr, msgString );
- }
- }
-
- #if kCompileWithExtraQC
- theQCErr = QCBlockBoundsCheckNow ();
- theQCErr = QCHeapCheckNow ();
- #endif
-
- return newBuffer;
- } /* CGIWSAPIGetParam */
-
-
- /* RESOURCE FILE */
- /* If you need to access resources in the plug-in file's resource fork,
- you must first call 'CGIWSAPIUseMyResFile'. You must make certain that
- before you return from a custom function, or make a call to ProcessGiveTime,
- that you call 'CGIWSAPIResetResFile'.
- See the WSAPI documentation for an explanation of dealing with resource files. */
-
- /* Set the plug-in file's resource fork as the current resource file */
- p_export void
- CGIWSAPIUseMyResFile ( void )
- {
- my_assert ( vMyResFile != nil, "\pCGIWSAPIUseMyResFile: vMyResFile is nil" );
- my_assert ( !(vResFileSemaphore), "\pCGIWSAPIUseMyResFile: vResFileSemaphore is true" );
-
- if ( vResFileSemaphore )
- {
- my_assert ( vSavedResFile != nil, "\pCGIWSAPIUseMyResFile: vSavedResFile is nil" );
- }
- else
- {
- my_assert ( vSavedResFile == nil, "\pCGIWSAPIUseMyResFile: vSavedResFile is not nil" );
-
- vSavedResFile = CurResFile ();
- UseResFile ( vMyResFile );
- vResFileSemaphore = true;
- }
- } /* CGIWSAPIUseMyResFile */
-
- /* Reset the current resource fork to the one in use before the previous call to CGIWSAPIUseMyResFile */
- p_export void
- CGIWSAPIResetResFile ( void )
- {
- my_assert ( vMyResFile != nil, "\pCGIWSAPIResetResFile: vMyResFile is nil" );
- my_assert ( vSavedResFile != nil, "\pCGIWSAPIResetResFile: vSavedResFile is nil" );
- my_assert ( vResFileSemaphore, "\pCGIWSAPIResetResFile: vResFileSemaphore is false" );
-
- UseResFile ( vSavedResFile );
- vSavedResFile = nil;
- vResFileSemaphore = false;
- } /* CGIWSAPIResetResFile */
-
-
- /* */
- static WSAPI_ErrorCode
- cgiProcessWSAPI ( WSAPI_CommandPBPtr commandPtr )
- {
- WSAPI_ErrorCode theErr;
- CGIHdl theCGIHdl;
- #if kCompileWithExtraQC
- QCErr theQCErr;
- #endif
-
- /* Allocate the CGIHdl data structure - zeroing out its contents.
- This is a special case where we make a direct call to the WSAPI. */
- theCGIHdl = (CGIHdl) WSAPI_AllocateOSMemory ( commandPtr, sizeof(CGIrecord) );
- if ( theCGIHdl == NULL )
- {
- /* memory didn't allocate - can't process cgi */
- return (WSAPI_ErrorCode)memFullErr;
- }
-
- /* clear the new handle */
- HLock ( (Handle)theCGIHdl );
- memset ( *theCGIHdl, nil, sizeof(CGIrecord) );
- HUnlock ( (Handle)theCGIHdl );
-
-
- (*theCGIHdl)->wsapi = commandPtr;
- cgiSetRole ( theCGIHdl );
-
- cgiWSAPILoadParameters ( theCGIHdl );
-
- /* this is where the application specific cgi handling comes into play
- the function "CustomCGIProcess" must be provided by the user of this source code */
- CustomCGIProcess ( theCGIHdl );
-
- /* complete the sending of data */
- if ( (*theCGIHdl)->responseData != NULL )
- {
- /* there is data remaining to be sent. */
-
- HLock ( (Handle)theCGIHdl );
-
- #if kCompileWithCGIResponseDataAsHandle
- HLock ( (*theCGIHdl)->responseData );
- #endif
-
- theErr = WSAPI_SendHTTPData ( commandPtr,
- #if kCompileWithCGIResponseDataAsHandle
- *((*theCGIHdl)->responseData),
- #else
- (*theCGIHdl)->responseData,
- #endif
- (*theCGIHdl)->responseSize );
-
- #if kCompileWithCGIResponseDataAsHandle
- HUnlock ( (*theCGIHdl)->responseData );
- #endif
-
- HUnlock ( (Handle)theCGIHdl );
- }
- else if ( !((*theCGIHdl)->dataSent) )
- {
- /* the user's "CustomCGIProcess" failed to set the responseData
- and no data has been sent.
- // Return an error header. */
- //theErr = WSAPI_SendHTTPData ( commandPtr,
- // "HTTP/1.0 500 Error\r\n\r\n", 22 );
- //if ( theErr == WSAPI_I_NoErr )
- //{
- theErr = WSAPI_E_MessageNotHandled;
- //}
- }
-
- /* give time, then cgiPostProcess */
- ProcessGiveTime ( nil, true, theCGIHdl );
- cgiPostProcess ( theCGIHdl );
-
- /* deallocate memory */
- cgiDisposeRecord ( theCGIHdl );
-
- #if kCompileWithExtraQC
- theQCErr = QCBlockBoundsCheckNow ();
- theQCErr = QCHeapCheckNow ();
- #endif
-
- return theErr;
- } /* cgiProcessWSAPI */
-
-
- /* Load the cgi parameters from the WSAPI into theCGIHdl */
- static void
- cgiWSAPILoadParameters ( CGIHdl theCGIHdl )
- {
- WSAPI_CommandPBPtr commandPtr;
- #if kCompileWithCGIFormHandling && kCompileWithCGIFormAutoProcess && kCompileWithCGImethod && (kCompileWithCGIhttp_search_args || kCompileWithCGIpost_args)
- short fieldError;
- #endif
- #if kCompileWithExtraQC
- QCErr theQCErr;
- #endif
-
- HLockHi ( (Handle)theCGIHdl );
-
- commandPtr = (*theCGIHdl)->wsapi;
-
- /* the following section is where the parameters are pulled in from
- the server and assigned to the CGI Handle */
-
- /* '----' - direct parameter / path arguments:
- path_args - arguments to the URL after a $ */
- #if kCompileWithCGIpath_args
- (*theCGIHdl)->path_args = CGIWSAPIGetParam ( commandPtr,
- piPathArgKeyword, (*theCGIHdl)->path_args, NULL );
- #if kCompileWithCGIAutoDecode
- if ( (*theCGIHdl)->path_args != NULL )
- {
- CGIDecodeURLChars ( (*theCGIHdl)->path_args );
- }
- #endif
- #endif /* kCompileWithCGIpath_args */
-
- /* 'kfor' - search arguments:
- http_search_args - arguments to the URL after a ? */
- #if kCompileWithCGIhttp_search_args
- (*theCGIHdl)->http_search_args = CGIWSAPIGetParam ( commandPtr,
- piSearchArgKeyword, (*theCGIHdl)->http_search_args, NULL );
- /* leave decoding until after parsing of form fields */
- #endif
-
- /* 'user' - user name:
- username - authenticated user name */
- #if kCompileWithCGIusername
- CGIWSAPIGetParam ( commandPtr,
- piUserKeyword, (*theCGIHdl)->username, kCGIMaxusername );
- #endif
-
- /* 'pass' - password:
- password - authenticated password */
- #if kCompileWithCGIpassword
- CGIWSAPIGetParam ( commandPtr,
- piPasswordKeyword, (*theCGIHdl)->password, kCGIMaxpassword );
- #endif
-
- /* 'frmu' - from user:
- from_user - non-standard. e-mail address of remote user */
- #if kCompileWithCGIfrom_user
- CGIWSAPIGetParam ( commandPtr,
- piFromUser, (*theCGIHdl)->from_user, kCGIMaxfrom_user );
- #endif
-
- /* 'addr' - client address:
- client_address - IP address or domain name of remote client's host */
- #if kCompileWithCGIclient_address
- CGIWSAPIGetParam ( commandPtr,
- piAddressKeyword, (*theCGIHdl)->client_address, kCGIMaxclient_address );
- #endif
-
- /* 'post' - post arguments:
- post_args - */
- #if kCompileWithCGIpost_args
- (*theCGIHdl)->post_args = CGIWSAPIGetParam ( commandPtr,
- piPostKeyword, (*theCGIHdl)->post_args, NULL );
- /* leave decoding to after form parsing */
- #endif
-
- /* 'meth' - HTTP method:
- method - GET, POST, etc. Used to tell if post_args are valid */
- #if kCompileWithCGImethod
- (*theCGIHdl)->method = cgiWSAPIGetParamHTTPMethod ( theCGIHdl, piMethodKeyword );
- #endif
-
- /* 'svnm' - server name:
- server_name - name or IP address of this server */
- #if kCompileWithCGIserver_name
- CGIWSAPIGetParam ( commandPtr,
- piServerName, (*theCGIHdl)->server_name, kCGIMaxserver_name );
- #endif
-
- /* 'svpt' - server port:
- server_port - TCP/IP port number being used by this server */
- #if kCompileWithCGIserver_port
- CGIWSAPIGetParam ( commandPtr,
- piServerPort, &((*theCGIHdl)->server_port), sizeof(short) );
- #endif
-
- /* 'scnm' - script name:
- script_name - URL name of this script */
- #if kCompileWithCGIscript_name
- (*theCGIHdl)->script_name = CGIWSAPIGetParam ( commandPtr,
- piScriptName, (*theCGIHdl)->script_name, NULL );
- #if kCompileWithCGIAutoDecode
- if ( (*theCGIHdl)->script_name != NULL )
- {
- CGIDecodeURLChars ( (*theCGIHdl)->script_name );
- }
- #endif
- #endif
-
- /* 'ctyp' - content type:
- content_type - MIME content type of post_args */
- #if kCompileWithCGIcontent_type
- CGIWSAPIGetParam ( commandPtr,
- piContentType, (*theCGIHdl)->content_type, kCGIMaxcontent_type );
- #endif
-
- /* 'CLen' - content length:
- content_length - the content-length header field (if any) from HTTP request */
- #if kCompileWithCGIcontent_length
- CGIWSAPIGetParam ( commandPtr,
- piContentLength, &((*theCGIHdl)->content_length), sizeof(long) );
- #endif
-
- /* 'refr' - referer:
- referer - the URL of the page referencing this document */
- #if kCompileWithCGIreferer
- (*theCGIHdl)->referer = CGIWSAPIGetParam ( commandPtr,
- piRefererKeyword, (*theCGIHdl)->referer, NULL );
- #endif
-
- /* 'Agnt' - user agent:
- user_agent - the name and version of the WWW client software being used */
- #if kCompileWithCGIuser_agent
- CGIWSAPIGetParam ( commandPtr,
- piUserAgentKeyword, (*theCGIHdl)->user_agent, kCGIMaxuser_agent );
- #endif
-
- /* 'Kact' - action name:
- action - the name of the action (CGI or ACGI if not a user defined action) */
- #if kCompileWithCGIActionSupport
- CGIWSAPIGetParam ( commandPtr,
- piActionKeyword, (*theCGIHdl)->action, kCGIMaxaction );
- #endif
-
- /* 'Kapt' - action path:
- action_path - path to the action application */
- #if kCompileWithCGIActionSupport
- (*theCGIHdl)->action_path = CGIWSAPIGetParam ( commandPtr,
- piActionPathKeyword, (*theCGIHdl)->action_path, NULL );
- #endif
-
- /* 'Kcip' - client IP address:
- client_ip - the IP address of the client */
- #if kCompileWithCGIclient_ip
- CGIWSAPIGetParam ( commandPtr,
- piClientIPAddress, &((*theCGIHdl)->client_ip), sizeof(long) );
- #endif
-
- /* 'Kfrq' - full request:
- full_request - the full text of the request */
- #if kCompileWithCGIfull_request
- (*theCGIHdl)->full_request = CGIWSAPIGetParam ( commandPtr,
- piFullRequestKeyword, (*theCGIHdl)->full_request, NULL );
- #endif
-
- /* 'Kcid' - connection ID:
- connection - the ID of the server's connection with a client */
- #if kCompileWithCGISendPartial
- CGIWSAPIGetParam ( commandPtr,
- piConnectionID, &((*theCGIHdl)->connection), sizeof(long) );
- #endif
-
- /* '' - :
- fileMIMEType - */
- #if kCompileWithCGIfileMIMEType
- (*theCGIHdl)->fileMIMEType = CGIWSAPIGetParam ( commandPtr,
- piFileMIMEType, (*theCGIHdl)->fileMIMEType, NULL );
- #endif
-
- /* '' - :
- piServerField - */
- #if kCompileWithCGIserverField
- (*theCGIHdl)->serverField = CGIWSAPIGetParam ( commandPtr,
- piServerField, (*theCGIHdl)->serverField, NULL );
- #endif
-
- /* '' - :
- serverDirectoryPath - */
- #if kCompileWithCGIserverDirectoryPath
- (*theCGIHdl)->serverDirectoryPath = CGIWSAPIGetParam ( commandPtr,
- piServerDirectoryPath, (*theCGIHdl)->serverDirectoryPath, NULL );
- #endif
-
- /* '' - :
- urlPhysicalPath - */
- #if kCompileWithCGIurlPhysicalPath
- (*theCGIHdl)->urlPhysicalPath = CGIWSAPIGetParam ( commandPtr,
- piURLPhysicalPath, (*theCGIHdl)->urlPhysicalPath, NULL );
- #endif
-
- /* '' - :
- ifModifiedSince - */
- #if kCompileWithCGIifModifiedSince
- CGIWSAPIGetParam ( commandPtr,
- piIfModifiedSince, &((*theCGIHdl)->ifModifiedSince), sizeof(short) );
- #endif
-
- /* '' - :
- currentRealm - */
- #if kCompileWithCGIcurrentRealm
- CGIWSAPIGetParam ( commandPtr,
- piCurrentRealm, (*theCGIHdl)->currentRealm, 256 );
- #endif
-
- #if kCompileWithCGIFormHandling && kCompileWithCGIFormAutoProcess && kCompileWithCGImethod
- /* separate the form fields into an array */
- switch ( (*theCGIHdl)->method )
- {
- #if kCompileWithCGIhttp_search_args
- case HTTP_get :
- if ( (*theCGIHdl)->http_search_args != NULL )
- {
- (*theCGIHdl)->formFields = CGIFormFieldsFromArgs ( theCGIHdl,
- (*theCGIHdl)->http_search_args, &((*theCGIHdl)->totalFields),
- &fieldError );
- }
- break;
- #endif
-
- #if kCompileWithCGIpost_args
- case HTTP_post :
- if ( (*theCGIHdl)->post_args != NULL )
- {
- (*theCGIHdl)->formFields = CGIFormFieldsFromArgs ( theCGIHdl,
- (*theCGIHdl)->post_args, &((*theCGIHdl)->totalFields), &fieldError );
- }
- break;
- #endif
- }
- #endif /* kCompileWithCGIFormHandling && kCompileWithCGIFormAutoProcess && kCompileWithCGImethod */
-
- /* now that the possible need to use them for form fields is over, we can
- decode the search args */
- #if kCompileWithCGIAutoDecode && kCompileWithCGIhttp_search_args
- if ( (*theCGIHdl)->http_search_args != NULL )
- {
- CGIDecodeURLChars ( (*theCGIHdl)->http_search_args );
- }
- #endif
-
- #if kCompileWithExtraQC
- theQCErr = QCBlockBoundsCheckNow ();
- theQCErr = QCHeapCheckNow ();
- #endif
-
- HUnlock ( (Handle)theCGIHdl );
- } /* cgiWSAPILoadParameters */
-
-
- #if kCompileWithCGImethod
- /* private function to get an HTTPMethod from an AppleEvent parameter */
- static HTTPMethod
- cgiWSAPIGetParamHTTPMethod ( CGIHdl theCGIHdl, WSAPI_ParamKeywords which )
- {
- HTTPMethod theMethod;
- char * tempBuffer;
- int stringDiff;
-
- /* default to GET */
- theMethod = HTTP_get;
-
- tempBuffer = CGIWSAPIGetParam ( (*theCGIHdl)->wsapi, which, NULL, NULL );
- if ( tempBuffer != NULL )
- {
- stringDiff = strcmp ( tempBuffer, kCGIHTTPMethodPost );
- if ( stringDiff == nil )
- {
- theMethod = HTTP_post;
- goto EXIT_HTTP_METHOD;
- }
-
- stringDiff = strcmp ( tempBuffer, kCGIHTTPMethodGet );
- if ( stringDiff == nil )
- {
- theMethod = HTTP_get;
- goto EXIT_HTTP_METHOD;
- }
-
- stringDiff = strcmp ( tempBuffer, kCGIHTTPMethodConditionalGet );
- if ( stringDiff == nil )
- {
- theMethod = HTTP_getConditional;
- goto EXIT_HTTP_METHOD;
- }
-
- stringDiff = strcmp ( tempBuffer, kCGIHTTPMethodGetConditional );
- if ( stringDiff == nil )
- {
- theMethod = HTTP_getConditional;
- goto EXIT_HTTP_METHOD;
- }
- }
-
- EXIT_HTTP_METHOD:
-
- if ( tempBuffer != NULL )
- {
- CGIDisposePtr ( theCGIHdl, tempBuffer );
- }
-
- return theMethod;
- } /* cgiWSAPIGetParamHTTPMethod */
- #endif /* kCompileWithCGImethod */
-
-
- /* Write messages to the WebSTAR display console.
- Only operates when compiling in debug mode */
- #if kCompileWithDebugging
- static WSAPI_ErrorCode
- cgiWSAPIDebugMessage ( WSAPI_CommandPBPtr commandPtr, char *theMessage )
- {
- WSAPI_ErrorCode theErr;
-
- theErr = WSAPI_DisplayMessage ( commandPtr, theMessage );
-
- return theErr;
- } /* cgiWSAPIDebugMessage */
- #endif
-
- /* This routine must be implemented if compiling for WSAPI.
- This is only to be called from the main routine in the WSAPI_Lib. */
- WSAPI_ErrorCode
- WSAPI_Dispatch ( WSAPI_CommandPBPtr commandPtr )
- {
- WSAPI_ErrorCode theErr;
- char theString[80];
-
- /* check that the API versions match */
- if ( commandPtr->api_version < WSAPI_VERSION )
- {
- /* the server is probably too old and doesn't support the
- calls used by this plug-in */
- return WSAPI_E_MessageNotHandled;
- }
- else
- {
- theErr = WSAPI_I_NoErr;
-
- switch ( commandPtr->command )
- {
- case WSAPI_Register:
- my_assert ( (strlen(kMyCGIName)) < WSAPI_NAME_SIZE,
- "\pWSAPI_Dispatch:WSAPI_Register: kMyCGIName (\"MyConfiguration.h\") is too long" );
-
- // vMyResFile = nil;
- // vSavedResFile = nil;
-
- /* copy the plugin-name to the WSAPI command paramBlock */
- strcpy ( commandPtr->param.init.pluginName, kMyCGIName );
-
- /* register the plug-in with the server */
- theErr = CustomCGIWSAPIRegister ( commandPtr );
- break;
-
- case WSAPI_Init:
- vMyResFile = commandPtr->param.init.resRef;
- vSavedResFile = nil;
-
- my_assert ( vMyResFile != nil, "\pWSAPI_Dispatch:WSAPI_Init: vMyResFile is nil" );
-
- theErr = cgiWSAPIDebugMessage ( commandPtr, kMyCGIName ": WSAPI_Init event" );
-
- /* ••• determine gProcessFSSpec */
- // •••
-
- CGIWSAPIUseMyResFile ();
-
- PrefStartup ();
- theErr = (WSAPI_ErrorCode) InitCGIUtil ();
-
- /* call the custom initialization */
- theErr = (WSAPI_ErrorCode) CustomStartup ( commandPtr );
-
- CGIWSAPIResetResFile ();
-
- #if kCompileWithPeriodicTask
- if ( theErr == WSAPI_I_NoErr )
- {
- /* request idle time so that periodic task can execute */
- theErr = WSAPI_RequestIdleTime ( commandPtr, kSleepTimeForPeriodicTask );
- }
- #endif
- break;
-
- case WSAPI_Shutdown :
- // theErr = cgiWSAPIDebugMessage ( commandPtr, kMyCGIName ": WSAPI_Shutdown event" );
-
- theErr = (WSAPI_ErrorCode) QuitWSAPI ( commandPtr );
- break;
-
- case WSAPI_Idle :
- // theErr = cgiWSAPIDebugMessage ( commandPtr, kMyCGIName ": WSAPI_Idle event" );
-
- /* do any global processing on a regular basis here,
- outside the context of a specific connection with
- a HTTP client. */
- #if kCompileWithPeriodicTask
- ProcessPeriodicTask ();
- #endif
- break;
-
- case WSAPI_Run:
- // theErr = cgiWSAPIDebugMessage ( commandPtr, kMyCGIName ": WSAPI_Run event" );
-
- /* CGI processing starts here */
- switch ( commandPtr->param.run.role )
- {
- case WSAPI_CGI_Role :
- /* Handle the CGI Event */
- case WSAPI_PreProcessor_Role :
- /* acting as a pre-processor */
- case WSAPI_Error_Role :
- /* handling bad URL requests */
- case WSAPI_NoAccess_Role :
- /* handling requests denied by IP or domain */
- case WSAPI_Index_Role :
- /* handling a request for the default file */
-
- CGIWSAPIUseMyResFile ();
-
- theErr = cgiProcessWSAPI ( commandPtr );
-
- CGIWSAPIResetResFile ();
- break;
-
- /* PostProcessor, Security and Logging roles have no
- client to talk to, so are quite limited in what they
- are allowed to do. Refer to the WSAPI docs. */
- case WSAPI_PostProcessor_Role :
- /* acting as a post-processor */
- case WSAPI_Logging_Role :
- /* receiving log info */
- case WSAPI_Security_Role :
- /* performing an access authorization */
-
- default :
- sprintf ( theString, kMyCGIName ": called with unhandled role: %d", commandPtr->param.run.role );
- WSAPI_DisplayMessage ( commandPtr, theString );
- break;
- }
- break;
-
- case WSAPI_Emergency:
- /* Some sort of emergency has arisen, requiring the plug-in
- to do it's best to free up memory, release resources,
- close files, etc. */
- CustomEmergencyHandler ();
- break;
-
- case WSAPI_ServerStateChanged :
- /* one or more of the server's settings have changed.
- Take appropriate action if you
- depend on specific settings values. */
- // theErr = cgiWSAPIDebugMessage ( commandPtr, kMyCGIName ": WSAPI_ServerStateChanged event" );
- break;
-
- default:
- sprintf ( theString, kMyCGIName ": received bad message, %d", commandPtr->command );
- theErr = WSAPI_DisplayMessage ( commandPtr, theString );
- theErr = WSAPI_E_MessageNotHandled;
- break;
- }
- }
-
- return theErr;
- } /* WSAPI_Dispatch */
-
-
- #else /* not kCompilingForWSAPI */
- /** APPLE EVENT SUPPORT **/
- #pragma mark -
-
- /* AppleEvent Handler for the CGI WWWΩ-sdoc event */
- pascal OSErr
- cgiAESearchDoc ( AppleEvent *theAppleEvent, AppleEvent *theReply, long Reference )
- {
- #pragma unused (Reference)
- OSErr theErr;
- CGIHdl theCGIHdl;
- #if kCompileWithThreadedAppleEvents
- ThreadID theThread;
- #endif
- #if kCompileWithDebugLogging
- char tempStr[16];
- #endif
- #if kCompileWithExtraQC
- QCErr theQCErr;
- #endif
-
- /* we're handling a CGI event, so we're more busy now */
- ProcessIsMoreBusy ();
-
- /* reset 'quit on idle time' timer */
- ResetQuitIdleTimer();
-
- #if kCompileWithDebugLogging
- LogStringP ( "\p==================\rCGI Event Recieved\rTICKS: " );
- sprintf ( tempStr, "%d", TickCount() );
- LogStringBreak ( tempStr );
- LogStringBreakP ( "\p------------------" );
- #endif
-
- /* Allocate the CGIHdl data structure - zeroing out its contents. */
- /* it's okay to use NULL here because we're not compiling for WSAPI,
- so theCGIHdl that would normally go where NULL is isn't needed */
- theCGIHdl = (CGIHdl) CGINewHandleClear ( NULL, sizeof(CGIrecord), &theErr );
- if ( theCGIHdl == NULL )
- {
- /* memory didn't allocate - can't process cgi */
- //••• may be better to try to return the http error header here
- return theErr;
- }
-
- /* copy the apple event and reply records */
- (*theCGIHdl)->appleEvent = *theAppleEvent;
- (*theCGIHdl)->replyEvent = *theReply;
- // HLock ( (Handle)theCGIHdl );
- // theErr = AEDuplicateDesc ( theAppleEvent, &((*theCGIHdl)->appleEvent) );
- //• handle err?
- // theErr = AEDuplicateDesc ( theReply, &((*theCGIHdl)->replyEvent) );
- //• handle err?
- // HUnlock ( (Handle)theCGIHdl );
-
- #if kCompileWithThreadedAppleEvents
- #if kCompileWithThreadsOptional
- if ( gHasThreadMgr )
- {
- #endif
-
- /* It is necessary to suspend the AppleEvent in order to thread its
- processing because of some real weirdness with AEProcessAppleEvent
- not being "reentrant." This means you can't be processing multiple
- Apple Events at the same time, so they have to be 'suspended' if
- you want to deal with more than one (IE. multi-threaded processing). */
- theErr = AESuspendTheCurrentEvent ( theAppleEvent );
- if ( theErr == noErr)
- {
- (*theCGIHdl)->suspended = true;
- /* AppleEvent has been suspended, so we can spawn a thread for processing. */
- theErr = ThreadNewThreadFromPool ( cgiAESearchDocProcessThread,
- theCGIHdl, (void**)NULL, &theThread );
- }
-
- #if kCompileWithThreadsOptional
- }
- #endif
- #endif /* kCompileWithThreadedAppleEvents */
-
- #if kCompileWithThreadedAppleEvents
- #if kCompileWithThreadsOptional
- if ( !gHasThreadMgr || (theErr != noErr) )
- #else
- if ( theErr != noErr )
- #endif
- {
- #endif
-
- /* if threading isn't available, or the attempt to thread failed,
- or the attempt to suspend the AppleEvent failed,
- process the Apple Event without threading. */
- theErr = cgiAESearchDocProcess ( theCGIHdl );
-
- #if kCompileWithThreadedAppleEvents
- }
- else
- {
- /* we suspended the AE, and spawned the thread, now let's start it. */
- //••• YieldToThread ( theThread );
- }
- #endif
-
- #if kCompileWithExtraQC
- theQCErr = QCBlockBoundsCheckNow ();
- theQCErr = QCHeapCheckNow ();
- #endif
-
- return theErr;
- } /* cgiAESearchDoc */
-
-
- /* Entry point for cgi handler thread. */
- #if kCompileWithThreadedAppleEvents
- pascal void *
- cgiAESearchDocProcessThread ( void *threadParam )
- {
- OSErr theErr;
- ThreadID currentThread;
-
- my_assert ( threadParam != NULL,
- "\pCGIAESearchDocProcessThread: the CGI handle (threadParam) is NULL" );
-
- /* The threadParam is used to pass the CGIHdl. */
- theErr = cgiAESearchDocProcess ( (CGIHdl)threadParam );
-
- /* Find the ID of current thread and use DisposeThread to dispose of it so
- that my custom thread termination procedure will be used to recycle
- this thread's allocation for the thread pool. */
- GetCurrentThread ( ¤tThread );
- DisposeThread ( currentThread, (void *)theErr, true );
-
- /* This line below is actually irrelevant, since the DisposeThread call above
- will result in the immediate termination of this thread.
- I keep it in because a return result is needed for the compiler not to
- issue a warning (and I have the "treat all warnings as errors" flag set
- in my compiler, like every programmer should). */
- return (void *)theErr;
- } /* cgiAESearchDocProcessThread */
- #endif
-
- /* Process the CGI WWWΩ-sdoc event.
- theCGIHdl must be valid (non-nil) and unlocked.
- Responsible for ensuring that cgiAEComplete is called so CGIDisposeHandle
- will be called. */
- static OSErr
- cgiAESearchDocProcess ( CGIHdl theCGIHdl )
- {
- OSErr theErr;
- Ptr tempBuffer;
- AppleEvent * theAppleEvent;
- /* the 'fieldError' variable is only used if forms with auto-processing are on,
- the method parameter is used, and one or both of the http_search_args and
- post_args are used */
- #if kCompileWithCGIFormHandling && kCompileWithCGIFormAutoProcess && kCompileWithCGImethod && (kCompileWithCGIhttp_search_args || kCompileWithCGIpost_args)
- short fieldError;
- #endif
- #if kCompileWithExtraQC
- QCErr theQCErr;
- #endif
-
- my_assert ( theCGIHdl != NULL, "\pcgiAESearchDocProcess: theCGIHdl is NULL" );
-
- #if __profile__ && __MWERKS__
- gProfileOn = !( ProfilerInit( collectDetailed, bestTimeBase, 20, 5 ) );
- #endif
-
- /* reset 'quit on idle time' timer */
- ResetQuitIdleTimer();
-
- tempBuffer = CGINewPtr ( theCGIHdl, kCGIParamMaxSize, &theErr );
- if ( tempBuffer == NULL )
- {
- goto Exit_Complete;
- }
-
- my_assert ( (HGetState((Handle)theCGIHdl) & kMemoryHandleLockedFlag) == nil,
- "\pcgiAESearchDocProcess: theCGIHdl is already locked!" );
- HLockHi ( (Handle)theCGIHdl );
-
- /* copy the AppleEvent record into a local variable for faster access. */
- theAppleEvent = &((*theCGIHdl)->appleEvent);
-
- /* the following section is where the parameters are pulled from the CGI
- Apple Event and allocated in the CGI Handle */
-
- /* '----' - direct parameter:
- path_args - arguments to the URL after a $ */
- #if kCompileWithCGIpath_args
- theErr = AEGetParamString ( theAppleEvent, '----', &((*theCGIHdl)->path_args),
- (char *)tempBuffer, kCGIParamMaxSize );
- #if kCompileWithCGIAutoDecode
- if ( theErr == noErr )
- {
- CGIDecodeURLChars ( (*theCGIHdl)->path_args );
- }
- #endif
- #endif /* kCompileWithCGIpath_args */
-
- /* 'kfor' - search arguments:
- http_search_args - arguments to the URL after a ? */
- #if kCompileWithCGIhttp_search_args
- theErr = AEGetParamString ( theAppleEvent, kCGIhttp_search_args,
- &((*theCGIHdl)->http_search_args), (char *)tempBuffer, kCGIParamMaxSize );
- /* leave decoding to after parsing of form fields */
- #endif
-
- /* 'user' - user name:
- username - authenticated user name */
- #if kCompileWithCGIusername
- theErr = AEGetParamStringNoAlloc ( theAppleEvent, kCGIusername,
- (*theCGIHdl)->username, kCGIMaxusername );
- #endif
-
- /* 'pass' - password:
- password - authenticated password */
- #if kCompileWithCGIpassword
- theErr = AEGetParamStringNoAlloc ( theAppleEvent, kCGIpassword,
- (*theCGIHdl)->password, kCGIMaxpassword );
- #endif
-
- /* 'frmu' - from user:
- from_user - non-standard. e-mail address of remote user */
- #if kCompileWithCGIfrom_user
- theErr = AEGetParamStringNoAlloc ( theAppleEvent, kCGIfrom_user,
- (*theCGIHdl)->from_user, kCGIMaxfrom_user );
- #endif
-
- /* 'addr' - client address:
- client_address - IP address or domain name of remote client's host */
- #if kCompileWithCGIclient_address
- theErr = AEGetParamStringNoAlloc ( theAppleEvent, kCGIclient_address,
- (*theCGIHdl)->client_address, kCGIMaxclient_address );
- #endif
-
- /* 'post' - post arguments:
- post_args - */
- #if kCompileWithCGIpost_args
- theErr = AEGetParamString ( theAppleEvent, kCGIpost_args,
- &((*theCGIHdl)->post_args), (char *)tempBuffer, kCGIParamMaxSize );
- /* leave decoding to after form parsing */
- #endif
-
- /* 'meth' - HTTP method:
- method - GET, POST, etc. Used to tell if post_args are valid */
- #if kCompileWithCGImethod
- theErr = cgiAEGetParamHTTPMethod ( theAppleEvent, kCGImethod,
- &((*theCGIHdl)->method), (char *)tempBuffer, kCGIParamMaxSize );
- #endif
-
- /* 'svnm' - server name:
- server_name - name or IP address of this server */
- #if kCompileWithCGIserver_name
- theErr = AEGetParamStringNoAlloc ( theAppleEvent, kCGIserver_name,
- (*theCGIHdl)->server_name, kCGIMaxserver_name );
- #endif
-
- /* 'svpt' - server port:
- server_port - TCP/IP port number being used by this server */
- #if kCompileWithCGIserver_port
- theErr = AEGetParamShort ( theAppleEvent, kCGIserver_port,
- &((*theCGIHdl)->server_port), (char *)tempBuffer, kCGIParamMaxSize );
- #endif
-
- /* 'scnm' - script name:
- script_name - URL name of this script */
- #if kCompileWithCGIscript_name
- theErr = AEGetParamString ( theAppleEvent, kCGIscript_name,
- &((*theCGIHdl)->script_name), (char *)tempBuffer, kCGIParamMaxSize );
- #if kCompileWithCGIAutoDecode
- if ( theErr == noErr )
- {
- CGIDecodeURLChars ( (*theCGIHdl)->script_name );
- }
- #endif
- #endif
-
- /* 'ctyp' - content type:
- content_type - MIME content type of post_args */
- #if kCompileWithCGIcontent_type
- theErr = AEGetParamStringNoAlloc ( theAppleEvent, kCGIcontent_type,
- (*theCGIHdl)->content_type, kCGIMaxcontent_type );
- #endif
-
- /* 'refr' - referer:
- referer - the URL of the page referencing this document */
- #if kCompileWithCGIreferer
- theErr = AEGetParamString ( theAppleEvent, kCGIreferer,
- &((*theCGIHdl)->referer), (char *)tempBuffer, kCGIParamMaxSize );
- #endif
-
- /* 'Agnt' - user agent:
- user_agent - the name and version of the WWW client software being used */
- #if kCompileWithCGIuser_agent
- theErr = AEGetParamStringNoAlloc ( theAppleEvent, kCGIuser_agent,
- (*theCGIHdl)->user_agent, kCGIMaxuser_agent );
- #endif
-
- /* 'Kact' - action name:
- action - the name of the action (CGI or ACGI if not a user defined action) */
- #if kCompileWithCGIActionSupport
- theErr = AEGetParamStringNoAlloc ( theAppleEvent, kCGIaction,
- (*theCGIHdl)->action, kCGIMaxaction );
- #endif
-
- /* 'Kapt' - action path:
- action_path - path to the action application */
- #if kCompileWithCGIActionSupport
- theErr = AEGetParamString ( theAppleEvent, kCGIaction_path,
- &((*theCGIHdl)->action_path), (char *)tempBuffer, kCGIParamMaxSize );
- #endif
-
- /* 'Kcip' - client IP address:
- client_ip - the IP address of the client */
- #if kCompileWithCGIclient_ip
- theErr = AEGetParamStringNoAlloc ( theAppleEvent, kCGIclient_ip,
- (*theCGIHdl)->client_ip, kCGIMaxclient_ip );
- #endif
-
- /* 'Kfrq' - full request:
- full_request - the full text of the request */
- #if kCompileWithCGIfull_request
- theErr = AEGetParamString ( theAppleEvent, kCGIfull_request,
- &((*theCGIHdl)->full_request), (char *)tempBuffer, kCGIParamMaxSize );
- #endif
-
- /* 'Kcid' - connection ID:
- connection - the ID of the server's connection with a client */
- #if kCompileWithCGISendPartial
- theErr = AEGetParamLong ( theAppleEvent, kCGIconnection, &((*theCGIHdl)->connection) );
- #endif
-
- /* don't need the buffer any more */
- CGIDisposePtr ( theCGIHdl, tempBuffer );
-
- /* don't need to take the time to check for required parameters because
- the official CGI policy (as set by Chuck Shotton) says that all
- parameters are to be optional. Otherwise, we would call:
- theErr = AEFuncGotRequiredParams ( theAppleEvent ); */
-
- #if kCompileWithCGIActionSupport
- /* determine the role of the CGI */
- cgiSetRole ( theCGIHdl );
- #endif
-
- #if kCompileWithCGIFormHandling && kCompileWithCGIFormAutoProcess && kCompileWithCGImethod
- /* separate the form fields into an array */
- switch ( (*theCGIHdl)->method )
- {
- #if kCompileWithCGIhttp_search_args
- case HTTP_get :
- if ( (*theCGIHdl)->http_search_args != NULL )
- {
- (*theCGIHdl)->formFields = CGIFormFieldsFromArgs ( theCGIHdl,
- (*theCGIHdl)->http_search_args, &((*theCGIHdl)->totalFields),
- &fieldError );
- }
- break;
- #endif
-
- #if kCompileWithCGIpost_args
- case HTTP_post :
- if ( (*theCGIHdl)->post_args != NULL )
- {
- (*theCGIHdl)->formFields = CGIFormFieldsFromArgs ( theCGIHdl,
- (*theCGIHdl)->post_args, &((*theCGIHdl)->totalFields), &fieldError );
- }
- break;
- #endif
- }
- #endif /* kCompileWithCGIFormHandling && kCompileWithCGIFormAutoProcess && kCompileWithCGImethod */
-
- /* now that the possible need to use them for form fields is over, we can
- decode the search args */
- #if kCompileWithCGIAutoDecode && kCompileWithCGIhttp_search_args
- if ( (*theCGIHdl)->http_search_args != NULL )
- {
- CGIDecodeURLChars ( (*theCGIHdl)->http_search_args );
- }
- #endif
-
- HUnlock ( (Handle)theCGIHdl );
-
- #if kCompileWithDebugLogging
- CGILogData ( theCGIHdl );
- #endif
-
- /* this is where the application specific cgi handling comes into play
- the function "CustomCGIProcess" must be provided by the user of this source code */
- CustomCGIProcess ( theCGIHdl );
-
- Exit_Complete:
-
- #if __profile__ && __MWERKS__
- if ( gProfileOn )
- {
- ProfilerDump ( "\p" kProfileNameStr "-" kProcessorString ".prof" );
- ProfilerTerm ();
- }
- #endif
-
- #if kCompileWithThreadedAppleEvents
- if ( (*theCGIHdl)->suspended )
- {
- //••• might need to do something special when doing send partial
-
- /* We're in a suspended AppleEvent, so we'll need to resume the
- AppleEvent to have it complete and return the reply properly. */
- theErr = AEResumeTheCurrentEvent ( &((*theCGIHdl)->appleEvent),
- &((*theCGIHdl)->replyEvent), vCGIAEResumeCompleteUPP, (long)theCGIHdl );
- if ( theErr != noErr )
- {
- theErr = AEResumeTheCurrentEvent ( &((*theCGIHdl)->appleEvent),
- &((*theCGIHdl)->replyEvent), vCGIAEResumeCompleteUPP, (long)NULL );
- }
- }
- else
- {
- #endif
-
- /* We weren't suspended, but still need to take care of the AppleEvent
- reply record. */
- theErr = cgiAEComplete ( theCGIHdl, &((*theCGIHdl)->replyEvent) );
-
- #if kCompileWithThreadedAppleEvents
- }
- #endif
-
- /* reset 'quit on idle time' timer */
- ResetQuitIdleTimer();
-
- #if kCompileWithExtraQC
- theQCErr = QCBlockBoundsCheckNow ();
- theQCErr = QCHeapCheckNow ();
- #endif
-
- return theErr;
- } /* cgiAESearchDocProcess */
-
-
- /* Call the event completion function (cgiAEComplete) when resuming
- suspended AppleEvents. theReference must be a CGIHdl.
- The result returned from this function will be used as the result of the AppleEvent. */
- #if kCompileWithThreadedAppleEvents
- pascal OSErr
- cgiAEResumeComplete ( const AppleEvent *theAppleEvent, AppleEvent *theReply, long theReference )
- {
- #pragma unused (theAppleEvent,theReply)
- OSErr theErr;
-
- my_assert ( theReference != nil,
- "\pCGIAEResumeComplete: the CGI handle (theReference) is nil" );
-
- theErr = cgiAEComplete ( (CGIHdl)theReference, theReply );
-
- return theErr;
- } /* cgiAEResumeComplete */
- #endif
-
- /* Complete the CGI AppleEvent. theCGIHdl must be valid. */
- static OSErr
- cgiAEComplete ( CGIHdl theCGIHdl, AppleEvent *theReply )
- {
- OSErr theErr;
- #if kCompileWithDebugLogging
- char tempStr[16];
- #endif
- #if kCompileWithExtraQC
- QCErr theQCErr;
- #endif
-
- my_assert ( theCGIHdl != NULL, "\pcgiAEComplete: theCGIHdl is NULL" );
- my_assert ( (HGetState((Handle)theCGIHdl) & kMemoryHandleLockedFlag) == nil,
- "\pcgiAEComplete: theCGIHdl is already locked!" );
-
- HLock ( (Handle)theCGIHdl );
-
- #if kCompileWithCGISendPartial
- if ( (*theCGIHdl)->sendPartialActive )
- {
- /* we're using sendpartial */
- if ( !((*theCGIHdl)->sendPartialDone) )
- {
- if ( (*theCGIHdl)->responseData != NULL )
- {
- /* close off the send partial with the last of the custom responseData */
- theErr = CGISendData ( theCGIHdl, (*theCGIHdl)->responseData, (*theCGIHdl)->responseSize, false );
- }
- else
- {
- /* Need to close off the send partial with a !sendMore parameter in
- a send partial event */
- theErr = CGISendData ( theCGIHdl, NULL, nil, false );
- }
- }
- else
- {
- /* nothing to do since all of the data has been sent and the send partial
- connection has been closed */
- }
- }
- else
- {
- #endif /* kCompileWithCGISendPartial */
-
- if ( (*theCGIHdl)->responseData != NULL )
- {
- #if kCompileWithCGIActionSupport
- if ( (*theCGIHdl)->role != CGIRole_PostProcessor )
- {
- /* only return data if not in the PostProcessor role */
- #endif
-
- #if kCompileWithCGIResponseDataAsHandle
- my_assert ( (HGetState((Handle)((*theCGIHdl)->responseData)) & kMemoryHandleLockedFlag) == nil,
- "\pcgiAEComplete: (*theCGIHdl)->responseData is already locked!" );
- HLock ( (*theCGIHdl)->responseData );
- #endif
-
- /* If the user's "CustomCGIProcess" function set the responseData properly,
- return it. */
- theErr = AEPutParamPtr ( theReply, keyDirectObject, typeChar,
- #if kCompileWithCGIResponseDataAsHandle
- *((*theCGIHdl)->responseData),
- #else
- (Ptr)((*theCGIHdl)->responseData),
- #endif
- (*theCGIHdl)->responseSize );
-
- #if kCompileWithCGIResponseDataAsHandle
- HUnlock ( (*theCGIHdl)->responseData );
- #endif
-
- #if kCompileWithCGIActionSupport
- }
- #endif
- }
- else
- {
- #if kCompileWithCGIActionSupport
- switch ( (*theCGIHdl)->role )
- {
- case CGIRole_PostProcessor :
- case CGIRole_Logging : //• not sure this is where this belongs
- /* do nothing */
- break;
-
- case CGIRole_PreProcessor :
- case CGIRole_Security : //• not sure this is where this belongs
- case CGIRole_Error : //• not sure this is where this belongs
- case CGIRole_NoAccess : //• not sure this is where this belongs
- case CGIRole_Index : //• not sure this is where this belongs
- /* return an empty string to indicate no data */
- theErr = AEPutParamPtr ( theReply, keyDirectObject, typeChar, "", 0 );
- break;
-
- case CGIRole_CGI :
- default :
- #endif
-
- /* if the user's "CustomCGIProcess" failed to set the responseData properly,
- return an error header. */
- theErr = AEPutParamPtr ( theReply, keyDirectObject, typeChar,
- (Ptr)gHTTPHeaderErr, gHTTPHeaderErrSize );
-
- #if kCompileWithCGIActionSupport
- break;
- }
- #endif
- }
-
- #if kCompileWithCGISendPartial
- }
- #endif /* kCompileWithCGISendPartial */
-
- HUnlock ( (Handle)theCGIHdl );
-
- /* give time, then cgiPostProcess */
- ProcessGiveTime ( nil, true, theCGIHdl );
- cgiPostProcess ( theCGIHdl );
-
- #if kCompileWithDebugLogging
- CGILogData ( theCGIHdl );
- #endif
-
- /* deallocate memory */
- cgiDisposeRecord ( theCGIHdl );
-
- #if kCompileWithDebugLogging
- LogStringP ( "\p___________________\rCGI Event Completed\rTICKS: " );
- sprintf ( tempStr, "%d", TickCount() );
- LogStringBreak ( tempStr );
- LogStringBreakP ( "\p===================" );
- #endif
-
- /* we're done this CGI event, so we're less busy now */
- ProcessIsLessBusy ();
-
- #if kCompileWithExtraQC
- theQCErr = QCBlockBoundsCheckNow ();
- theQCErr = QCHeapCheckNow ();
- #endif
-
- return theErr;
- } /* cgiAEComplete */
-
-
- #if kCompileWithCGImethod
- /* private function to get an HTTPMethod from an AppleEvent parameter */
- static OSErr
- cgiAEGetParamHTTPMethod ( const AppleEvent *theAppleEvent, AEKeyword theAEKeyword, HTTPMethod *theMethod, char *tempBuffer, long bufferSize )
- {
- OSErr theErr;
- DescType actualType;
- Size actualSize;
- int stringDiff;
-
- my_assert ( theMethod != NULL, "\pcgiAEGetParamHTTPMethod: theMethod ptr is NULL" );
- my_assert ( theAppleEvent != NULL, "\pcgiAEGetParamHTTPMethod: theAppleEvent ptr is NULL" );
- my_assert ( tempBuffer != NULL, "\pcgiAEGetParamHTTPMethod: tempBuffer ptr is NULL" );
-
- theErr = AEGetParamPtr ( theAppleEvent, theAEKeyword, typeChar,
- &actualType, (Ptr)tempBuffer, bufferSize, &actualSize );
- if ( theErr == noErr )
- {
- my_assert ( actualSize <= bufferSize,
- "\pcgiAEGetParamHTTPMethod: actual param size too big" );
-
- /* terminate the buffer with a null byte */
- tempBuffer[actualSize] = nil;
-
- /* compare the buffer with constants to determine the http method used */
-
- stringDiff = strcmp ( tempBuffer, kCGIHTTPMethodPost );
- if ( stringDiff == nil )
- {
- *theMethod = HTTP_post;
-
- return noErr;
- }
-
- stringDiff = strcmp ( tempBuffer, kCGIHTTPMethodGet );
- if ( stringDiff == nil )
- {
- *theMethod = HTTP_get;
-
- return noErr;
- }
-
- stringDiff = strcmp ( tempBuffer, kCGIHTTPMethodConditionalGet );
- if ( stringDiff == nil )
- {
- *theMethod = HTTP_getConditional;
-
- return noErr;
- }
-
- stringDiff = strcmp ( tempBuffer, kCGIHTTPMethodGetConditional );
- if ( stringDiff == nil )
- {
- *theMethod = HTTP_getConditional;
-
- return noErr;
- }
- }
-
- *theMethod = HTTP_UNDEFINED;
-
- return theErr;
- } /* cgiAEGetParamHTTPMethod */
- #endif
-
-
- #endif /* not kCompilingForWSAPI */
-
-
- /** MISC **/
- #pragma mark -
-
- /* set the role field of theCGIHdl */
- #if kCompileWithCGIActionSupport || kCompilingForWSAPI
- static void
- cgiSetRole ( CGIHdl theCGIHdl )
- {
- #if !(kCompilingForWSAPI)
- int stringDifference;
- #endif
-
- my_assert ( theCGIHdl != NULL, "\pcgiSetRole: theCGIHdl is NULL" );
-
- #if kCompilingForWSAPI
-
- my_assert ( (*theCGIHdl)->wsapi->command == WSAPI_Run, "\pcgiSetRole: not in run mode" );
-
- (*theCGIHdl)->role = (CGIRole)((*theCGIHdl)->wsapi->param.run.role);
-
- #else /* if not kCompilingForWSAPI */
-
- if ( (*theCGIHdl)->action == NULL )
- {
- /* no action defined - set role to CGI */
- (*theCGIHdl)->role = CGIRole_CGI;
- return;
- }
-
- /* CGI */
- stringDifference = strcmp ( (*theCGIHdl)->action, kCGIActionNameCGI );
- if ( stringDifference == nil )
- {
- (*theCGIHdl)->role = CGIRole_CGI;
- return;
- }
-
- /* ACGI */
- stringDifference = strcmp ( (*theCGIHdl)->action, kCGIActionNameACGI );
- if ( stringDifference == nil )
- {
- (*theCGIHdl)->role = CGIRole_CGI;
- return;
- }
-
- /* PreProcessor */
- stringDifference = strcmp ( (*theCGIHdl)->action, kCGIActionNamePreProcessor );
- if ( stringDifference == nil )
- {
- (*theCGIHdl)->role = CGIRole_PreProcessor;
- return;
- }
-
- /* PostProcessor */
- stringDifference = strcmp ( (*theCGIHdl)->action, kCGIActionNamePostProcessor );
- if ( stringDifference == nil )
- {
- (*theCGIHdl)->role = CGIRole_PostProcessor;
- return;
- }
-
- /* Logging */
- stringDifference = strcmp ( (*theCGIHdl)->action, kCGIActionNameLogging );
- if ( stringDifference == nil )
- {
- (*theCGIHdl)->role = CGIRole_Logging;
- return;
- }
-
- /* Security */
- stringDifference = strcmp ( (*theCGIHdl)->action, kCGIActionNameSecurity );
- if ( stringDifference == nil )
- {
- (*theCGIHdl)->role = CGIRole_Security;
- return;
- }
-
- /* Error */
- stringDifference = strcmp ( (*theCGIHdl)->action, kCGIActionNameError );
- if ( stringDifference == nil )
- {
- (*theCGIHdl)->role = CGIRole_Error;
- return;
- }
-
- /* NoAccess */
- stringDifference = strcmp ( (*theCGIHdl)->action, kCGIActionNameNoAccess );
- if ( stringDifference == nil )
- {
- (*theCGIHdl)->role = CGIRole_NoAccess;
- return;
- }
-
- /* Index */
- stringDifference = strcmp ( (*theCGIHdl)->action, kCGIActionNameIndex );
- if ( stringDifference == nil )
- {
- (*theCGIHdl)->role = CGIRole_Index;
- return;
- }
-
- /* some unrecognized role - default to CGI */
- (*theCGIHdl)->role =CGIRole_CGI;
-
- #endif /* kCompilingForWSAPI */
- } /* cgiSetRole */
- #endif
-
-
- /** CLEAN UP **/
- #pragma mark -
-
- /* */
- static void
- cgiPostProcess ( CGIHdl theCGIHdl )
- {
- CustomCGIPostProcess ( theCGIHdl );
- } /* cgiPostProcess */
-
-
- /** Memory Allocation Cleanup **/
-
- /* */
- static void
- cgiDisposeRecord ( CGIHdl theCGIHdl )
- {
- #if kCompileWithExtraQC
- QCErr theQCErr;
- #endif
- #if !(kCompilingForWSAPI)
- // OSErr theErr;
- #endif
-
- my_assert ( theCGIHdl != NULL, "\pcgiDisposeRecord: theCGIHdl is NULL" );
- my_assert ( *theCGIHdl != NULL, "\pcgiDisposeRecord: *theCGIHdl is NULL" );
-
- /* the following is a bunch of statements checking if a parameter has been
- allocated and disposing of it if it has */
-
- #if kCompileWithCGIpath_args
- if ( (*theCGIHdl)->path_args != NULL )
- {
- CGIDisposePtr ( theCGIHdl, (Ptr)((*theCGIHdl)->path_args) );
- }
- #endif
- #if kCompileWithCGIhttp_search_args
- if ( (*theCGIHdl)->http_search_args != NULL )
- {
- CGIDisposePtr ( theCGIHdl, (Ptr)((*theCGIHdl)->http_search_args) );
- }
- #endif
- #if kCompileWithCGIpost_args
- if ( (*theCGIHdl)->post_args != NULL )
- {
- CGIDisposePtr ( theCGIHdl, (Ptr)((*theCGIHdl)->post_args) );
- }
- #endif
- #if kCompileWithCGIscript_name
- if ( (*theCGIHdl)->script_name != NULL )
- {
- CGIDisposePtr ( theCGIHdl, (Ptr)((*theCGIHdl)->script_name) );
- }
- #endif
- #if kCompileWithCGIreferer
- if ( (*theCGIHdl)->referer != NULL )
- {
- CGIDisposePtr ( theCGIHdl, (Ptr)((*theCGIHdl)->referer) );
- }
- #endif
-
- #if kCompileWithCGIActionSupport
- if ( (*theCGIHdl)->action_path != NULL )
- {
- CGIDisposePtr ( theCGIHdl, (Ptr)((*theCGIHdl)->action_path) );
- }
- #endif
-
- #if kCompileWithCGIfull_request
- if ( (*theCGIHdl)->full_request != NULL )
- {
- CGIDisposePtr ( theCGIHdl, (Ptr)((*theCGIHdl)->full_request) );
- }
- #endif
-
- #if kCompileWithCGIfileMIMEType
- if ( (*theCGIHdl)->fileMIMEType != NULL )
- {
- CGIDisposePtr ( theCGIHdl, (Ptr)((*theCGIHdl)->fileMIMEType) );
- }
- #endif
-
- #if kCompileWithCGIserverField
- if ( (*theCGIHdl)->serverField != NULL )
- {
- CGIDisposePtr ( theCGIHdl, (Ptr)((*theCGIHdl)->serverField) );
- }
- #endif
-
- #if kCompileWithCGIserverDirectoryPath
- if ( (*theCGIHdl)->serverDirectoryPath != NULL )
- {
- CGIDisposePtr ( theCGIHdl, (Ptr)((*theCGIHdl)->serverDirectoryPath) );
- }
- #endif
-
- #if kCompileWithCGIurlPhysicalPath
- if ( (*theCGIHdl)->urlPhysicalPath != NULL )
- {
- CGIDisposePtr ( theCGIHdl, (Ptr)((*theCGIHdl)->urlPhysicalPath) );
- }
- #endif
-
- #if kCompileWithCGIFormHandling
- if ( (*theCGIHdl)->formFields != NULL )
- {
- CGIFormFieldsDispose ( theCGIHdl, (*theCGIHdl)->formFields );
- }
- #endif
-
- #if kCompilingForWSAPI
-
- #else
- if ( (*theCGIHdl)->appleEvent.descriptorType != nil )
- {
- //• HLock ( (Handle)theCGIHdl );
- //• theErr = AEDisposeDesc ( &((*theCGIHdl)->appleEvent) );
- //• HUnlock ( (Handle)theCGIHdl );
- //• deal with any errs?
- }
- // if ( (*theCGIHdl)->replyEvent.descriptorType != nil )
- // {
- // theErr = AEDuplicateDesc ( theReply, &((*theCGIHdl)->replyEvent) );
- // //• handle err?
- // }
- #endif
-
- if ( (*theCGIHdl)->responseData != NULL )
- {
- #if kCompileWithCGIResponseDataAsHandle
- CGIDisposeHandle ( theCGIHdl, (*theCGIHdl)->responseData );
- #else
- CGIDisposePtr ( theCGIHdl, (Ptr)((*theCGIHdl)->responseData) );
- #endif
- }
-
- CGIDisposeHandle ( theCGIHdl, (Handle)theCGIHdl );
-
- #if kCompileWithExtraQC
- theQCErr = QCBlockBoundsCheckNow ();
- theQCErr = QCHeapCheckNow ();
- #endif
- } /* cgiDisposeRecord */
-
-
- #endif /* kCompileWithCGICode */
-
- /*** EOF ***/
-